Flutter动画 3 - Animation动画组

_animation = Tween(begin: 0, end: 50).animate(_animationController)
…addListener(() {
setState(() {});
});
_colorAnimationController = AnimationController(duration: Duration(milliseconds: 600), vsync: this);
_colorAnimation = ColorTween(begin: Colors.orangeAccent, end: Colors.redAccent).animate(_colorAnimationController)
…addListener(() {
setState(() {});
});

最后,我们只需要监听位移动画完成状态之后执行颜色动画即可,具体代码如下所示.

_animationController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_colorAnimationController.forward();
};
});

整体Demo代码如下所示.

class _FlutterAnimationWidgetState extends State with TickerProviderStateMixin {
AnimationController _animationController;
Animation _animation;
AnimationController _colorAnimationController;
Animation _colorAnimation;

@override
void initState() {
super.initState();
_animationController = AnimationController(duration: Duration(milliseconds: 300), vsync: this);
_animation = Tween(begin: 0, end: 50).animate(_animationController)
…addListener(() {
setState(() {});
});
_colorAnimationController = AnimationController(duration: Duration(milliseconds: 600), vsync: this);
_colorAnimation = ColorTween(begin: Colors.orangeAccent, end: Colors.redAccent).animate(_colorAnimationController)
…addListener(() {
setState(() {});
});
_animationController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_colorAnimationController.forward();
};
});
}

void startEasyAnimation() {
_animationController.forward();
}

@override
void dispose() {
_animationController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 200,
height: 50,
color: _colorAnimation.value,
margin: EdgeInsets.only(top: _animation.value),
),
FlatButton(
onPressed: startEasyAnimation,
child: Text(
“点击执行最简单动画”,
style: TextStyle(color: Colors.black38),
),
),
],
),
),
);
}
}

Interval时间间隔法

上面的状态监听需要一个动画过程就写一个Controller,而且基本上还要每一个Controller都监听执行完成然后再去启动下一个Controller.如果一个动画过程有十几个,自己想想都是脑瓜子嗡嗡的.所以接下来我们就来介绍第二种方案 - Interval时间间隔法 .

Interval时间间隔法 的整体思路是一个动画Controller控制所有动画的执行.然后每一个动画只需要确认自己在整个动画的时间比重即可.

首先,声明一个动画Controller和多个动画.

AnimationController _animationController;
Animation _animation;
Animation _colorAnimation;

然后初始化AnimationController,AnimationController的动画时间(duration)要设置成所有动画的总时长,例如这里我设定为600毫秒(_animation时长:300毫秒,_colorAnimation时长:300毫秒).

_animationController = AnimationController(duration: Duration(milliseconds: 600), vsync: this);

接下来就是初始化两个Animation,Tween对象调用animate()函数不再是直接传入上面的AnimationController,而是传入一个CurvedAnimation 对象.CurvedAnimation构建过程中需要传入两个参数一个是 parent ,用于指定AnimationController. 另外一个是 curve,用于指定动画曲线函数.我们可以使用常用的动画曲线函数,也可以自己生成,这里我们就自己生成.指定动画执行的时间区间.

// CurvedAnimation的构建方法
CurvedAnimation({
required this.parent,
required this.curve,
this.reverseCurve,
}) : assert(parent != null),
assert(curve != null) {
_updateCurveDirection(parent.status);
parent.addStatusListener(_updateCurveDirection);
}

由于两个动画时间长度是对分的,每一个都是300毫秒,所以 curve 参数中的值就分别是 Interval(0.0, 0.5)Interval(0.5, 1.0),两个Animation的初始化过程如下所示.

_animation = Tween(begin: 0, end: 50).animate(
CurvedAnimation(
parent: _animationController,
curve: Interval(0.0, 0.5),
),
)…addListener(() {
setState(() {});
});

_colorAnimation = ColorTween(begin: Colors.orangeAccent, end: Colors.redAccent).animate(
CurvedAnimation(
parent: _animationController,
curve: Interval(0.5, 1.0),
),
)…addListener(() {
setState(() {});
});

整体Demo代码如下所示.

class _FlutterAnimationWidgetState extends State with TickerProviderStateMixin {
AnimationController _animationController;
Animation _animation;
Animation _colorAnimation;

@override
void initState() {
super.initState();
_animationController = AnimationController(duration: Duration(milliseconds: 600), vsync: this);
_animation = Tween(begin: 0, end: 50).animate(
CurvedAnimation(
parent: _animationController,
curve: Interval(0.0, 0.5),
),
)…addListener(() {
setState(() {});
});
_colorAnimation = ColorTween(begin: Colors.orangeAccent, end: Colors.redAccent).animate(
CurvedAnimation(
parent: _animationController,
curve: Interval(0.5, 1.0),
),
)…addListener(() {
setState(() {});
});
}

void startEasyAnimation() {
_animationController.forward();
}

@override
void dispose() {
_animationController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 200,
height: 50,
color: _colorAnimation.value,
margin: EdgeInsets.only(top: _animation.value),
),
FlatButton(
onPressed: startEasyAnimation,
child: Text(
“点击执行最简单动画”,
style: TextStyle(color: Colors.black38),
),
),
],
),
),
);
}
}

TweenSequence动画序列法

上面的两种方案虽然能解决动画组的问题,但是都太过于繁琐,那么有没有一种比较优雅的方案呢?这就需要使用到 TweenSequenceTweenSequenceItem 这两个类了. 其中 TweenSequence 是动画组类,TweenSequenceItem 则是用来定义每一个动画的具体实现的类.但是TweenSequenceTweenSequenceItem也不是尽善尽美的,它最大的问题就是前后变化的属性值类型必须是一致的.

下面,我们仍然以改变Margin为例, 先让视图组件往上移动50,再让视图 来看看如何使用 TweenSequenceTweenSequenceItem 来实现这个动画.

首先,我们声明一个 动画控制器AnimationController 和 动画Animation.

AnimationController _animationController;
Animation _animation;

仍然以两者的动画总时长为600毫秒,所以我们需要实现AnimationController,如下所示.

_animationController = AnimationController(duration: Duration(milliseconds: 600), vsync: this);

然后,我们通过 TweenSequenceTweenSequenceItem 这两个类对 动画Animation 进行实现.

实现两个 TweenSequenceItem, TweenSequenceItem中的 weight 属性是来设定动画执行的时间权重.也就是在整个动画过程,当前动画执行时长占总时长的比例.例如下面 第一个动画插值占的时间比例为 50/(50 + 100). 第二个动画插值占的时间比例为 100/(50 + 100) .

TweenSequenceItem downMarginItem = TweenSequenceItem(
tween: Tween(begin: 1.0, end: 50.0),
weight: 50,
);
TweenSequenceItem upMarginItem = TweenSequenceItem(
tween: Tween(begin: 50.0, end: 100.0),
weight: 100,
);

然后创建一个动画插值组,把上面两个动画插值放入组中.

TweenSequence tweenSequence = TweenSequence([
downMarginItem,
upMarginItem,
]);

最后,生成动画就OK了.

_animation = tweenSequence.animate(_animationController);
_animation.addListener(() {
setState(() {});
});

当然了,上面的三步可以缩写成一步代码来实现,我只是进行了分解代码来说明每一个代码.

// 缩写代码
_animation = TweenSequence([
TweenSequenceItem(
tween: Tween(begin: 0.0, end: 50.0),
weight: 50,
),
TweenSequenceItem(
tween: Tween(begin: 50.0, end: 100.0),
weight: 100,
),
]).animate(_animationController)
…addListener(() {
setState(() {});
});

整体代码如下所示.

class _FlutterAnimationWidgetState extends State with TickerProviderStateMixin {
AnimationController _animationController;
Animation _animation;

@override
void initState() {
super.initState();
_animationController = AnimationController(duration: Duration(milliseconds: 600), vsync: this);
TweenSequenceItem downMarginItem = TweenSequenceItem(
tween: Tween(begin: 1.0, end: 50.0),
weight: 50,
);
TweenSequenceItem upMarginItem = TweenSequenceItem(
tween: Tween(begin: 50.0, end: 100.0),
weight: 100,
);
TweenSequence tweenSequence = TweenSequence([
downMarginItem,
upMarginItem,
]);
_animation = tweenSequence.animate(_animationController);
_animation.addListener(() {
setState(() {});
});
}

void startEasyAnimation() {
_animationController.forward();
}

@override
void dispose() {
_animationController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 200,
height: 50,
color: Colors.orangeAccent,
margin: EdgeInsets.only(top: _animation.value),
),
FlatButton(
onPressed: startEasyAnimation,
child: Text(
“点击执行最简单动画”,
style: TextStyle(color: Colors.black38),
),
),
],
),
),
);
}
}

动画组实现总结
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值