Flutter Dojo设计之道——骚气的闪屏动画是如何实现的
这篇文章是对Flutter动画实现思路的一篇剖析,用一个简单的动画,分析Flutter创建动画的一般步骤
闪屏,实际上有两个作用。
宣传。通过Logo、广告等形式,在启动时,展示要宣传的广告等内容。 后台初始化。借助这个时间做一些后台操作,初始化一些SDK或者代码。
Flutter Dojo的闪屏动画,参考了著名大厂——P站的App闪屏,相信大家应该都不陌生。
动画其实比较简单,只是一个从两边向中间靠拢的动画。
一般来说,Flutter的动画创作,有下面几个步骤。
创建静态布局 创建Tween,标记动画的起始值 给静态代码添加AnimatedBuilder,驱动动画
静态布局
这个布局没有什么太大难度,这个效果其实有很多实现方案,比如Center-Row的方式,让【Flutter】Text和【Dojo】Text在Row中居中即可。或者可以用Stack-Positioned的方式,通过left、right来定位。
相比来说,Center-Row的方式会比较直观,所以我这里准备使用Stack-Positioned的方式来进行演示。
不管使用哪种方案,需要注意的一点是,【Flutter】Text和【Dojo】Text是整体居中的,并不是分别居中,因为【Flutter】Text比【Dojo】Text要长,所以沿屏幕中线居中会很不协调。
布局之外,需要稍微提下【Dojo】Text的实现,实际上就是通过BoxDecoration来实现的,代码如下所示。
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Color.fromARGB(255, 253, 152, 39),
),
定义动画
这里的动画分为两部分,左边和右边,如果使用Center-Row的方式,由于两个Text并不在屏幕中线对齐,所以实际上是有个offset的,然后再通过Transform.translate来进行偏移。另一种方式,Stack-Positioned实际上也是如此,但是可以通过Positioned中的left和right来进行动画。
所以首先一步,需要获取【Flutter】Text和【Dojo】Text的宽度差,这里又有多种方式来获取一个Widget的Size了。
LayoutBuilder。由于需要提前创建动画,所以这个方案不是很好。 TextPainter。对于文字,可以使用TextPainter来进行文本的测量。 Key。通过Key来获取RenderBox,从而获取Widget的Size。
Key的方式比较简单,所以这里我准备用TextPainter的方式来演示。下面这个函数就演示了如何获取一个特定TextStyle下Text的计算宽度。
double getTextWidth(String text) {
final textPainter = TextPainter(
text: TextSpan(
text: text,
style: TextStyle(
fontSize: 60,
fontWeight: FontWeight.w600,
),
),
textDirection: TextDirection.ltr,
);
textPainter.layout(minWidth: 0, maxWidth: double.infinity);
return textPainter.width;
}
经过简单的计算,【Flutter】Text和【Dojo】Text偏移的值实际上就是两个文本的宽度差的一半。
由于前面使用的是Stack-Positioned的方式进行的布局,所以动画也需要根据静态布局来定义。
先看【Flutter】Text的动画,它从屏幕左边作用到中间带偏移的地方,所以其动画值的范围是:
begin: screenWidth, end: screenWidth / 2 - offset
相应的,【Dojo】Text的动画,也类似:
begin: screenWidth, end: screenWidth / 2 + offset
动画管理
在确定的动画值的范围之后,实际上Tween就已经确定了,这里介绍一个动画管理的技巧,通过一个类来封装Widget所需要的不同的Tween,这样可以将动画的逻辑和Widget进行解耦,代码如下所示。
import 'package:flutter/material.dart';
class SplashAnimManager {
final AnimationController controller;
final Animation animLeft;
final Animation animRight;
final double screenWidth;
final double offset;
SplashAnimManager(this.controller, this.screenWidth, this.offset)
: animLeft = Tween(begin: screenWidth, end: screenWidth / 2 - offset).animate(
CurvedAnimation(
parent: controller,
curve: Curves.easeIn,
),
),
animRight = Tween(begin: screenWidth, end: screenWidth / 2 + offset).animate(
CurvedAnimation(
parent: controller,
curve: Curves.easeIn,
),
);
}
这里仅仅是为了演示这种动画管理的思想,才将仅仅两个动画写在了管理类中。
实际上Flutter Dojo中有很多地方都是这样,不仅仅可以从App上学习Flutter的相关知识,通过阅读Dojo的源码,你会发现更多。
动画组装
最后就是通过AnimatedBuilder来进行组装,动画的本质实际上就是不断修改某个属性的值,从而产生动画的效果。【Flutter】Text和【Dojo】Text也是一样,以【Flutter】Text为例,实际上就是right属性从Tween的begin到end进行变化,所以,给静态布局套上AnimatedBuilder,再给相应的属性设置Tween的值就可以了,代码如下所示。
@override
Widget build(BuildContext context) {
final double screenWidth = MediaQuery.of(context).size.width;
_splashAnimManager = SplashAnimManager(
_animationController,
screenWidth,
(getTextWidth('Flutter') - getTextWidth('Dojo') - 4) / 2,
);
return Container(
alignment: Alignment.center,
color: Colors.black,
child: Stack(
fit: StackFit.expand,
alignment: Alignment.center,
children: [
AnimatedBuilder(
animation: _animationController,
builder: (context, widget) {
return Positioned(
right: _splashAnimManager.animLeft.value,
child: Text(
'Flutter',
style: TextStyle(
fontSize: 60,
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
);
},
),
AnimatedBuilder(
animation: _animationController,
builder: (context, widget) {
return Positioned(
left: _splashAnimManager.animRight.value,
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 4,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Color.fromARGB(255, 253, 152, 39),
),
child: Text(
'Dojo',
style: TextStyle(
fontSize: 60,
fontWeight: FontWeight.w600,
color: Colors.black,
),
),
),
);
},
),
],
),
);
}
以上,一个骚气的闪屏动画就完成了。
代码地址
https://github.com/xuyisheng/flutter_dojo/blob/master/lib/pages/splash/slpash.dart
修仙
Flutter Dojo开源至今,受到了很多Flutter学习者和爱好者的喜爱,也有越来越多的人加入到Flutter的学习中来,所以我建了个Flutter修仙群,但是人数太多,所以分成了【Flutter修仙指南】【Flutter修仙指北】【Flutter修仙指东】三个群,对Flutter感兴趣的朋友,可以添加我的微信,注明加入Flutter修仙群,或者直接关注我的微信公众号【Android群英传】。
项目地址:
https://github.com/xuyisheng/flutter_dojo
- END -