内容简介:还记得上一节 里面是怎么更新这一次我们使用看代码:
还记得上一节 里面是怎么更新 widget 的状态的吗?我们上次的步骤是:首先创建动画,然后给动画添加监听 addListener(...) , 在 addListener(...) 方法中我们干了件 很重要 的事儿: setState((){}) ,因为只有调用这个,才会让 widget 重绘。
这一次我们使用 AnimatedWidget 来实现动画,使用它就不需要给动画 addListener(...) 和 setState((){}) 了, AnimatedWidget 自己会使用当前 Animation 的 value 来绘制自己。当然,这里 Animation 我们是以构造参数的方式传递进去的。
看代码:
class AnimatedContainer extends AnimatedWidget {
AnimatedContainer({Key key, Animation<double> animation})
: super (key: key, listenable: animation);
@override
Widget build(BuildContext context) {
final Animation<double> animation = listenable;
return Center(
child: Container(
decoration: BoxDecoration(
color: Colors.redAccent
),
margin: EdgeInsets.symmetric(vertical: 10.0),
height: animation.value,
width: animation.value,
),
);
}
}
复制代码
上述代码中,我们定义了一个 AnimatedContainer 继承了 AnimatedWidget ,然后定义了一个构造方法,注意,构造方法中我们定义了一个 Animation 然后把这个 Animation 传到父类(super)中去了,我们可以看看 listenable: animation 这个参数,是一个 Listenable 类型,如下:
/// The [Listenable] to which this widget is listening. /// /// Commonly an [Animation] or a [ChangeNotifier]. final Listenable listenable; 复制代码
然后再看看 Animation 类:
abstract class Animation<T> extends Listenable implements ValueListenable<T> {
...
}
复制代码
可以看到 Animation 是 Listenable 的子类,所以在我们自定义的 AnimatedContainer 类中可以传一个 Animation 类型的的参数作为父类中 listenable 的值。
使用我们上面定义的 AnimatedContainer 也很简单,直接作为 widget 使用就好,部分代码如下:
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AnimatedWidgetDemo',
theme: ThemeData(
primaryColor: Colors.redAccent
),
home: Scaffold(
appBar: AppBar(
title: Text('AnimatedWidgetDemo'),
),
body: AnimatedContainer(animation: animation,)
),
);``
}
复制代码
可以看出我们在实例化 AnimatedContainer 的时候传入了一个 Animation 对象。
效果如下:
AnimatedBuilder
我们先看看如何使用 AnimatedBuilder 做一个上面一样的效果
部分代码如下:
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AnimatedBuilderExample',
theme: ThemeData(primaryColor: Colors.redAccent),
home: Scaffold(
appBar: AppBar(
title: Text('animatedBuilderExample'),
),
body: Center(
child: AnimatedBuilder(
animation: _animation,
child: Container(
decoration: BoxDecoration(color: Colors.redAccent),
),
builder: (context, child) {
return Container(
width: _animation.value,
height: _animation.value,
child: child,
);
},
),
),
),
);
}
复制代码
因为 AnimatedBuilder 是继承于 AnimatedWidget 的,
class AnimatedBuilder extends AnimatedWidget { ... }
复制代码
所以可以直接把 AnimatedBuilder 当作 widget 使用
上述代码关键部分如下:
body: Center(
child: AnimatedBuilder(
animation: _animation,
child: Container(
decoration: BoxDecoration(color: Colors.redAccent),
),
builder: (context, child) {
return Container(
width: _animation.value,
height: _animation.value,
child: child,
);
},
),
),
复制代码
效果如下:
builder 这个匿名类是每次动画值改变的时候就会被调用
AnimatedBuilder使用简化后的结构如下:
AnimatedBuilder(
animateion: ... ,
child: ... ,
builder: (context, child) {
return Container(
width: ... ,
height: ... ,
child: child
)
}
)
复制代码
上述代码看着可能会有迷糊的地方,里面的 child 好像被指定了两次,外面一个,里面一个。其实,外面的 child 是传给 AnimatedBuilder 的,而 AnimatedBuilder 又将这个 child 作为参数传递给了里面的匿名类( builder )。
我们可以验证上述说明,就是给外面的 child 指定一个 key ,然后在 builder 里面打印出参数 child 的 key 。
body: Center(
child: AnimatedBuilder(
animation: _animation,
child: Container(
decoration: BoxDecoration(color: Colors.redAccent),
key: Key("android"),
),
builder: (context, child) {
print("child.key: ${child.key}");
return Container(
width: _animation.value,
height: _animation.value,
child: child,
);
},
),
),
复制代码
我们在外面的 child 里面的添加了一个 key 值,然后在 builder 里面打印出参数 child 的 key 值
输出如下:
flutter: child.key: [<'android'>] 复制代码
区别
我们来看看 AnimatedBuilder AnimatedWidget 和添加 addListener{} 监听并在里面触发 setState(...) 这三种方式做动画有什么区别。
为了更直观的看出它们的区别,这里使用一个第三方控件: RandomContainer ,这个控件会在屏幕每次重绘的时候改变自身的颜色。
首先在 pubspec.yaml 中添加依赖 random_pk: any ,如下:
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
# RandomContainer
random_pk: any
复制代码
先写一个小例子来看看 RandomContainer 这个控件每次在屏幕重绘的时候自身颜色改变的情况。
在屏幕上绘制一个宽高都为 200.0 的 RandomContainer 然后给 RandomContainer 添加点击事件,点击事件里面做的就是调用 setState(...) 让 widget 重绘,部分代码如下:
body: Center(
child: GestureDetector(
onTap: _changeColor,
child: RandomContainer(
width: 200.0,
height: 200.0,
),
),
),
复制代码
使用 RandomContainer 的时候需要引入 import 'package:random_pk/random_pk.dart';
点击事件代码如下:
void _changeColor() {
setState(() {});
}
复制代码
效果如下:
接下来我们使用三种方式实现同一种效果来看看有什么不同:
AnimatedWidget
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 5))
..repeat();
复制代码
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AnimatedBuilder',
theme: ThemeData(primaryColor: Colors.redAccent),
home: Scaffold(
appBar: AppBar(
title: Text('AnimatedBuilder'),
),
body: Center(
child: RandomContainer(
width: 200.0,
height: 200.0,
child: AnimatedWidgetDemo( // new
animation: _controller,
),
),
),
),
);
}
复制代码
效果如下:
AnimatedBuilder
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 5))
..repeat();
复制代码
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AnimatedBuilder',
theme: ThemeData(primaryColor: Colors.redAccent),
home: Scaffold(
appBar: AppBar(
title: Text('AnimatedBuilder'),
),
body: Center(
child: RandomContainer(
width: 200.0,
height: 200.0,
child: AnimatedBuilderDemo( // new
child: getContainer(),
animation: _controller,
),
),
),
),
);
}
复制代码
AnimatedBuilder的效果和 AnimatedWidget 的效果是一样的。
接下来我们看看在 addListener{} 里面调用 setState(...) 的效果,也就是我们在上一节中实现动画的方式
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 5))
..repeat()
..addListener(() {
setState(() {});
});
复制代码
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AnimatedBuilder',
theme: ThemeData(primaryColor: Colors.redAccent),
home: Scaffold(
appBar: AppBar(
title: Text('AnimatedBuilder'),
),
body: Center(
child: RandomContainer(
width: 200.0,
height: 200.0,
child: Transform.rotate( // new
child: getContainer(),
angle: _controller.value * 2.0 * pi,
),
),
),
),
);
}
复制代码
效果如下
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Masterminds of Programming
Federico Biancuzzi、Chromatic / O'Reilly Media / 2009-03-27 / USD 39.99
Description Masterminds of Programming features exclusive interviews with the creators of several historic and highly influential programming languages. Think along with Adin D. Falkoff (APL), Jame......一起来看看 《Masterminds of Programming》 这本书的介绍吧!