内容简介:话不多少,直接上效果通过观察可以发现这个动画分为三个过程
思路参考自: 扔物线
整体效果
话不多少,直接上效果
通过观察可以发现这个动画分为三个过程
- 过程一: 底部翘起来
- 过程二: 转起来
过程三:右边翘起来
三维图像投影到二维平面
图片绕着 x 轴旋转,左侧视图为旋转后投影到二位平面的图片,右侧为旋转过程中的三维视图。
过程一
可以把图片分成上下两部分,上半边完全没动,下半部分绕着 x 轴旋转,不断改变转动角度就可以达到过程一的效果
过程二
过程二稍复杂,先看其中某一帧的情况
红线下半部分翘起来了,上半部分没有翘起来,所以考虑分为上下两部分绘制
下半部分
- 图片绕着 z 轴旋转 20 度
- 裁剪图片,只取下半部分
- 图片绕着 x 轴旋转 45 度
- 图片绕着 z 轴旋转 -20 度
上半部分
- 图片绕着 z 轴旋转 20 度
- 裁剪图片,只取上半部分
- 图片绕着 x 轴旋转 0 度(为什么?为了和其他过程统一过程,方便代码编写)
- 图片绕着 z 轴旋转 -20 度
拼接
把这两部分图拼接起来就是过程二中某一帧的效果
实现过程二的动画
保持每一帧 绕着 x 轴旋转的角度固定,改变绕着 z 轴旋转的角度就可以实现过程二的动画。
改进过程一(方便代码编写)
过程一下半部分
- 图片绕着 z 轴旋转 0 度
- 裁剪图片,只取下半部分
- 图片绕着 x 轴旋转某个角度
- 图片绕着 z 轴旋转 0 度
不断改变 x 轴旋转的角度就可以就可以实现过程一中下半部分的动画效果
过程一上半部分
- 图片绕着 z 轴旋转 0 度
- 裁剪图片,只取上半部分
- 图片绕着 x 轴旋转 0 度
- 图片绕着 z 轴旋转 0 度
过程三
过程三和过程一类似,不再赘述。
整个动画具体参数
-
过程一:
- 上半部分:旋转角度都是 0
- 下半部分:绕 z 轴旋转角度始终为 0,绕 x 轴旋转角度从 0 过渡到 -45 度
-
过程二:
- 上半部分:绕着 z 轴旋转角度从 0 过渡到270 度,绕着 x 轴旋转的角度固定为 0 度
- 下半部分:绕着 z 轴旋转角度从 0 过渡到270 度,绕着 x 轴旋转的角度固定为 -45 度
-
过程三
- 上半部分:绕 z 轴旋转角度始终为 270 度,绕 x 轴旋转角度从 0 过渡到 45 度
- 下半部分:绕 z 轴旋转角度始终为 270 度,绕 x 轴旋转角度始终为 0 度
代码编写
首先定义一个enum,标识动画当前进行到那个过程
enum FlipAnimationSteps { animation_step_1, animation_step_2, animation_step_3 }
复制代码
设置动画参数,监听动画状态
class _FlipAnimationApp extends State<FlipAnimationApp>
with SingleTickerProviderStateMixin {
var imageWidget = Image.asset(
'images/mario.jpg',
width: 300.0,
height: 300.0,
);
AnimationController controller;
CurvedAnimation animation;
@override
void initState() {
super.initState();
controller =
AnimationController(duration: const Duration(seconds: 1), vsync: this);
animation = CurvedAnimation(
parent: controller,
curve: Curves.easeInOut,
)..addStatusListener((status) {
if (status == AnimationStatus.completed) {
switch (currentFlipAnimationStep) {
case FlipAnimationSteps.animation_step_1:
currentFlipAnimationStep = FlipAnimationSteps.animation_step_2;
controller.reset();
controller.forward();
break;
case FlipAnimationSteps.animation_step_2:
currentFlipAnimationStep = FlipAnimationSteps.animation_step_3;
controller.reset();
controller.forward();
break;
case FlipAnimationSteps.animation_step_3:
break;
}
}
});
controller.forward();
}
@override
Widget build(BuildContext context) {
return AnimateFlipWidget(
animation: animation,
child: imageWidget,
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
复制代码
再来看看核心类 AnimateFlipWidget ,动画相关的主要逻辑都在里面。
class AnimateFlipWidget extends AnimatedWidget {
final Widget child;
double _currentTopRotationXRadian = 0;
double _currentBottomRotationXRadian = 0;
double _currentRotationZRadian = 0;
static final _topRotationXRadianTween =
Tween<double>(begin: 0, end: math.pi / 4);
static final _bottomRotationXRadianTween =
Tween<double>(begin: 0, end: -math.pi / 4);
static final _rotationZRadianTween =
Tween<double>(begin: 0, end: (1 + 1 / 2) * math.pi);
AnimateFlipWidget({Key key, Animation<double> animation, this.child})
: super(key: key, listenable: animation);
@override
Widget build(BuildContext context) {
final Animation<double> animation = listenable;
return Center(
child: Container(
child: Stack(
children: [
Transform(
alignment: Alignment.center,
transform: Matrix4.rotationZ(currentFlipAnimationStep ==
FlipAnimationSteps.animation_step_2
? _rotationZRadianTween.evaluate(animation) * -1
: _currentRotationZRadian * -1),
child: Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.002)
..rotateX(currentFlipAnimationStep ==
FlipAnimationSteps.animation_step_3
? _currentTopRotationXRadian =
_topRotationXRadianTween.evaluate(animation)
: _currentTopRotationXRadian),
alignment: Alignment.center,
child: ClipRect(
clipper: _TopClipper(context),
child: Transform(
alignment: Alignment.center,
transform: Matrix4.rotationZ(currentFlipAnimationStep ==
FlipAnimationSteps.animation_step_2
? _currentRotationZRadian =
_rotationZRadianTween.evaluate(animation)
: _currentRotationZRadian),
child: child,
),
),
),
),
Transform(
alignment: Alignment.center,
transform: Matrix4.rotationZ(currentFlipAnimationStep ==
FlipAnimationSteps.animation_step_2
? _rotationZRadianTween.evaluate(animation) * -1
: _currentRotationZRadian * -1),
child: Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.002)
..rotateX(currentFlipAnimationStep ==
FlipAnimationSteps.animation_step_1
? _currentBottomRotationXRadian =
_bottomRotationXRadianTween.evaluate(animation)
: _currentBottomRotationXRadian),
alignment: Alignment.center,
child: ClipRect(
clipper: _BottomClipper(context),
child: Transform(
alignment: Alignment.center,
transform: Matrix4.rotationZ(currentFlipAnimationStep ==
FlipAnimationSteps.animation_step_2
? _currentRotationZRadian =
_rotationZRadianTween.evaluate(animation)
: _currentRotationZRadian),
child: child,
),
),
),
),
],
),
),
);
}
}
复制代码
这个类返回了一个 Stack 布局,可以把上半部分和下半部分的变换结果叠加在一起(注意:不能用 Column 布局哦), children 里面的两个 Transform 就是上下两部分变化之后的结果。可以发现两个 Transform 都是符合前面的变换流程(绕 Z 轴旋转 - > 裁剪 -> 绕 X 轴旋转 -> 绕 Z 轴转回来)。
看一下下半部分裁剪的过程
class _BottomClipper extends CustomClipper<Rect> {
final BuildContext context;
_BottomClipper(this.context);
@override
Rect getClip(Size size) {
return new Rect.fromLTRB(
-size.width, size.height / 2, size.width * 2, size.height * 2);
}
@override
bool shouldReclip(CustomClipper<Rect> oldClipper) {
return true;
}
}
复制代码
定义一个类,继承CustomClipper类,重写getClip指定具体的裁剪范围。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- CSS3实现卡片翻转动画效果
- 简单几步,用纯CSS3实现3D翻转效果!
- 神奇的数字“3”:一次翻转3个比特即可实现Rowhammer攻击
- canvas 图像旋转与翻转姿势解锁
- canvas 图像旋转与翻转姿势解锁
- 图解:K 个一组翻转链表
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
郎咸平说:新经济颠覆了什么
郎咸平 / 东方出版社 / 2016-8 / 39.00元
正所谓“上帝欲其灭亡,必先令其疯狂”,在当下中国,“互联网+资本催化”的新经济引擎高速运转,大有碾压一切、颠覆一切之势。在新经济狂热之下,每个人都在全力以赴寻找“下一个风口”,幻想成为下一只飞起来的猪。 对此,一向以“危机论”著称的郎咸平教授再次发出盛世危言:新经济光环背后,危机已悄然而至!中国式O2O还能烧多久?P2P监管黑洞有多大?互联网造车为什么不靠谱?共享经济为什么徒有虚名?BAT为......一起来看看 《郎咸平说:新经济颠覆了什么》 这本书的介绍吧!