1.An AnimatedBuilder understands how to render the transition. —— AnimatedBuilder 知道如何渲染转场动效。
2.An AnimatedBuilder doesn’t know how to render the widget, nor does it manage the Animation object. —— AnimatedBuilder 不知道(或者准确说不应)如何渲染组件,也不管理组件对象。
3.Use AnimatedBuilder to describe an animation as part of a build method for another widget. If you simply want to define a widget with a reusable animation, use an AnimatedWidget. —— 使用 AnimatedBuilder 作为其他组件的动效描述。如果只是想复用一个带有动效的组件,那么应该使用 AnimatedWidget。
const AnimatedBuilder({ Key? key, required Listenable animation, required this.builder, this.child, }) : assert(animation != null), assert(builder != null), super(key: key, listenable: animation);其中关键的参数是builder,builder 用于构建组件的转变动作,在 builder 里可以对要渲染的子组件进行转变操作,然后返回变换后的组件。builder 的定义如下,其中 child 实际就是 AnimatedBuilder 的 child 参数,可以根据需要是否使用。
Widget Function(BuildContext context, Widget? child)
const Transform({ Key? key, required this.transform, this.origin, this.alignment, this.transformHitTests = true, Widget? child, }) : assert(transform != null), super(key: key, child: child);这里的参数说明如下:
//堆代码 duidaima.com class RotationSwitchAnimatedBuilder extends StatelessWidget { final Widget child1, child2; final Animation<double> animation; const RotationSwitchAnimatedBuilder( {Key? key, required this.animation, required this.child1, required this.child2}) : super(key: key); @override Widget build(BuildContext context) { return AnimatedBuilder( animation: animation, builder: (context, child) { if (animation.value < 0.5) { return Transform( transform: Matrix4.identity() ..rotateZ(animation.value * pi) ..setEntry(0, 1, -0.003), alignment: Alignment.center, child: child1, ); } else { return Transform( transform: Matrix4.identity() ..rotateZ(pi) ..rotateZ(animation.value * pi) ..setEntry(1, 0, 0.003), child: child2, alignment: Alignment.center, ); } }, ); } }注意第 2 个组件多转了 180 度,是未来保证停止后正好旋转 360 度,以免图片倒过来。另外就是这里的 child1和 child2也可以修改为使用 WidgetBuilder 函数来在需要的时候再构建组件。使用这个RotationSwitchAnimatedBuilder的组件就十分简单了,将需要操作的两个组件作为参数传过来,然后控制 Animation 对象来刷新界面就好了,对应的代码如下:
// 堆代码 duidaima.com class AnimatedBuilderDemo extends StatefulWidget { const AnimatedBuilderDemo({Key? key}) : super(key: key); @override _AnimatedBuilderDemoState createState() => _AnimatedBuilderDemoState(); } class _AnimatedBuilderDemoState extends State<AnimatedBuilderDemo> with SingleTickerProviderStateMixin { late Animation<double> animation; late AnimationController controller; @override void initState() { super.initState(); controller = AnimationController(duration: const Duration(seconds: 1), vsync: this); animation = Tween<double>(begin: 0, end: 1.0).animate(controller); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('AnimatedBuilder 动画'), ), body: RotationSwitchAnimatedBuilder( animation: animation, child1: Center( child: Container( padding: EdgeInsets.all(10), margin: EdgeInsets.all(10), constraints: BoxConstraints(minWidth: double.infinity), decoration: BoxDecoration( borderRadius: BorderRadius.circular(4.0), gradient: LinearGradient( colors: [ Colors.orange, Colors.green, ], ), ), child: Text( '点击按钮变出小姐姐', style: TextStyle( fontSize: 20, color: Colors.white, fontWeight: FontWeight.bold, ), textAlign: TextAlign.center, ), ), ), child2: Center( child: Image.asset('images/beauty.jpeg'), ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.play_arrow, color: Colors.white), onPressed: () { if (controller.status == AnimationStatus.completed) { controller.reverse(); } else { controller.forward(); } }, ), ); } @override void dispose() { controller.dispose(); super.dispose(); } }复用的话也很容易了,比如我们将一个圆形和一个矩形组件传过去,一样可以复用这个动画效果。