如今的Flutter正是如火中天,昨天Google官方正式发布了
Flutter1.7
版本,主要包含了对Android X的支持和Play Store的一些更新,一些新的和加强的组件,以及一些问题的修复。android
本篇文章咱们一块儿开发一个炫炫的列表展现,伴随着滚动,背景作一些相应的动画效果。先看下效果图:git
列表滚动的时候,获取垂直方向的滚动距离,再将这个值转化成角度单位带动齿轮的滚动github
Flutter的项目都是从lib/main.dart
开始:bash
import 'package:flutter/material.dart'; import 'demo-card.dart'; import 'items.dart'; import 'animated-bg.dart'; void main() => runApp(AnimationDemo()); class AnimationDemo extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: MyHomePage(title: '列表滚动'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { ScrollController _controller = new ScrollController(); List<DemoCard> get _cards => items.map((Item _item) => DemoCard(_item)).toList(); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, appBar: AppBar(title: Text(widget.title)), body: Stack( alignment: AlignmentDirectional.topStart, children: <Widget>[ AnimatedBackground(controller: _controller), Center( child: ListView(controller: _controller, children: _cards), ) ], ), ); } } 复制代码
在main.dart
文件中,有几个import进来的文件:markdown
demo-card.dart
卡片widget,列表就是循环的这个widgetitems.dart
卡片展现的数据放在这个文件中,本项目咱们写了点mock数据,真实生产项目的数据更可能是从http请求animated-bg.dart
背景齿轮的widget这个文件主要使用了一些Flutter的基础widget,有不清楚的同窗能够去官网查下使用方法, 另外,列表渲染的时候须要注意下,咱们会使用ScrollController _controller = new ScrollController();
从而获取垂直方向滚动的距离app
为了省事,咱们直接将数据放在lib/items.dart
里,咱们模拟了六条数据,main.dart里的listView的children就是使用这六条数据生成的:less
import 'package:flutter/material.dart'; class Item { String name; MaterialColor color; IconData icon; Item(this.name, this.color, this.icon); } List<Item> items = [ Item('壹', Colors.amber, Icons.adjust), Item('贰', Colors.cyan, Icons.airport_shuttle), Item('叁', Colors.indigo, Icons.android), Item('肆', Colors.green, Icons.beach_access), Item('伍', Colors.pink, Icons.attach_file), Item('陸', Colors.blue, Icons.bug_report) ]; 复制代码
三个字段:ide
咱们在main.dart
里这么生成列表的children:items.map((Item _item) => DemoCard(_item)).toList();
对DemoCard传入参数_item,其实就是React或者Vue里面的props。不一样之处在于,flutter传入的参数既能够是匿名的也能够是具名的,这里咱们用的是匿名传参。看下卡片Widget怎么接收参数:oop
import 'package:flutter/material.dart'; import 'items.dart'; class DemoCard extends StatelessWidget { DemoCard(this.item); final Item item; static final Shadow _shadow = Shadow(offset: Offset(2.0, 2.0), color: Colors.black26); final TextStyle _style = TextStyle(color: Colors.white70, shadows: [_shadow]); @override Widget build(BuildContext context) { return Card( elevation: 3, shape: RoundedRectangleBorder( side: BorderSide(width: 1, color: Colors.black26), borderRadius: BorderRadius.circular(32), ), color: item.color.withOpacity(.7), child: Container( constraints: BoxConstraints.expand(height: 256), child: RawMaterialButton( onPressed: () {}, child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, crossAxisAlignment: CrossAxisAlignment.stretch, children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[ Text(item.name, style: _style.copyWith(fontSize: 64)), Icon(item.icon, color: Colors.white70, size: 72), ], ) ], ), ), ), ); } } 复制代码
定义了一个StatelessWidget,对应React或者Vue就是无状态组件,接收参数的方式是在构造器上声明,这种方式和ES6一致:布局
DemoCard(this.item);
final Item item;
复制代码
使用Card组件能够快速的还原一张卡片样式
elevation
参数控制卡片悬浮高度shape
参数控制卡片圆角color
参数控制卡片背景,item.color.withOpacity(.7)
让背景透明化30%而后就是使用Column和Row来控制布局的展现
先看下背景组件的源码,再一一解释:
import 'package:flutter/material.dart'; class AnimatedBackground extends StatefulWidget { AnimatedBackground({Key key, this.controller}) : super(key: key); final ScrollController controller; @override _AnimatedBackgroundState createState() => _AnimatedBackgroundState(); } class _AnimatedBackgroundState extends State<AnimatedBackground> { get offset => widget.controller.hasClients ? widget.controller.offset : 0; @override Widget build(BuildContext context) { return AnimatedBuilder( animation: widget.controller, builder: (BuildContext context, Widget child) { return OverflowBox( maxWidth: double.infinity, alignment: Alignment(4, 3), child: Transform.rotate( angle: offset / -512, child: Icon(Icons.settings, size: 512, color: Colors.white), ), ); }, ); } } 复制代码
这个controller
是在main.dart里传下来的,它是ListView的controller,咱们用widget.controller.offset
便可拿到垂直方向上的滚动距离。 列表滚动时咱们要不停的刷新齿轮的转动角度,因此咱们选用AnimatedBuilder
组件,组件有两个重要参数:
OverflowBox组件能够经过alignment(锚点)很好的控制子组件的显示位置,这里咱们使用Alignment(4, 3)
将齿轮定位到屏幕左下方。 让齿轮真正动起来的是Transform.rotate
组件,这里有个弧长公式要用到:L=α(弧度)× r(半径),因此咱们这么使用:angle: offset / -512
size: 512
篇幅有限,不能一一展开讲解使用到的组件,有问题的同窗自行去官网查看用法哦
本篇文章能学到Flutter不少知识,包括:StatelessWidget/StatefulWidget的建立、本地数据的建立和使用、列表的展现和控制、垂直水平布局等等,想看效果的同窗能够直接跑源码哦