今天给大家带来的是径向Hero动画,我本来对动画就不敏感,刚看到的时候都准备放弃了,准备放弃时干了一碗鸡汤,终于通过一上午的时间,搞出来了,我感觉我是太牛了!!,接下来就看看效果吧~
效果图
先来看看今天完成的效果图吧:
效果图(1.1):
分析步骤
先来分析步骤:
- 2个界面,一张小图圆形背景,一张用Card包裹的大图方形背景
- 从小圆圆形页面跳转到大方形页面
- 大圆方形页面外层由Card包裹
- 小圆跳转到大方页面透明度由0变化到1,大方形页面也如此
- 大方形页面返回时,由方形变化到圆形
- 水波纹点击时效果
页面搭建
第一步: 咋们先不管什么方形圆形的,先来吧2个页面的布局给写出来
class Radial_hero_animaiton_demo_page extends StatefulWidget {
@override
_Radial_hero_animaiton_demo_pageState createState() =>
_Radial_hero_animaiton_demo_pageState();
}
class _Radial_hero_animaiton_demo_pageState extends State<Radial_hero_animaiton_demo_page> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("径向Hero动画"),
),
body: initRadialHeroBody(),
);
}
}
/**
* body 布局
*/
Widget initRadialHeroBody() {
return Container(
padding: EdgeInsets.all(30),
//布局排列到考下,靠左的位置
alignment: Alignment.bottomLeft,
//左右排列布局
child: Row(
children: [
//圆形布局
ClipOval(
child: Material(
color: Colors.teal,
child: InkWell(
child: Image.network("https://raw.githubusercontent.com/flutter/website/master/examples/_animation/radial_hero_animation/images/chair-alpha.png",
width: 70,
height: 70,
),
onTap: () {},
),
),
)
],
));
}
这段代码没什么问题,只要学一个月flutter肯定能随手就来,就不解释了
方形布局页面:
import 'dart:math' as math;
class JumpHeroPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("JumpHeroPage页面"),
),
//Center居中布局
body: Center(
//使用卡片布局
child: Card(
child: Column(
//设置最小宽度
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 300,
height: 300,
child: Container(
alignment: Alignment.center,
//方形布局
child: ClipRect(
child: Container(
width: 2 * (300 / 2 / math.sqrt2),
height: 2 * (300 / 2 / math.sqrt2),
child: Material(
color: Colors.teal,
//水波纹效果
child: InkWell(
child: Image.network(
"https://raw.githubusercontent.com/flutter/website/master/examples/_animation/radial_hero_animation/images/chair-alpha.png"),
onTap: () {
},
),
)),
),
),
),
],
),
),
));
}
}
如果布局有不熟悉的朋友可以查看Flutter 如何进行Flutter布局开发(1.3),在本篇中我对布局做了简单的介绍.
有细心的同学可能会问了正方形为什么要用:
width: 2 * (300 / 2 / math.sqrt2),
height: 2 * (300 / 2 / math.sqrt2),
这两行是什么意思,您呀不要着急,后面我会对这里详细的解释的.
这里需要注意的是,在使用Cloumn()组件时,这个地方需要加mainAxisSize:MainAxisSize.min,参数,这里代表的意思相当于andorid中的wrap_content会自适应布局的宽和高:否则就会变成效果图(1.2)的样子:
效果图(1.2);
走到这里就完成了两个页面的布局以及水波纹效果,对水波纹效果不熟悉的朋友可以查看Flutter Ink,InkWell,InkResponse水波纹实现(2.3)来对水波纹进行了解.
第二步:接下来使用Hero动画,完成2个页面的联动
class Radial_hero_animaiton_demo_page extends StatefulWidget {
@override
_Radial_hero_animaiton_demo_pageState createState() =>
_Radial_hero_animaiton_demo_pageState();
}
class _Radial_hero_animaiton_demo_pageState extends State<Radial_hero_animaiton_demo_page> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("径向Hero动画"),
),
body: initRadialHeroBody(),
);
}
/**
* body 布局
*/
Widget initRadialHeroBody() {
return Container(
padding: EdgeInsets.all(30),
alignment: Alignment.bottomLeft,
child: Row(
children: [
Hero(
tag: "RadialHeroAnimation",
//圆形布局
child: ClipOval(
child: Container(
child: Material(
color: Colors.teal,
child: InkWell(
child: Image.network("https://raw.githubusercontent.com/flutter/website/master/examples/_animation/radial_hero_animation/images/chair-alpha.png",
width: 70,
height: 70,
),
onTap: () {
},
),
),
)),
),
],
));
}
}
大方形Hero动画:
class JumpHeroPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("JumpHeroPage页面"),
),
body: Center(
//使用卡片布局
child: Card(
child: Column(
//设置最小宽度
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 300,
height: 300,
child: Hero(
tag: "RadialHeroAnimation",
//圆形布局
child: ClipOval(
child: Container(
alignment: Alignment.center,
//方形布局
child: ClipRect(
child: Container(
width: 2 * (300 / 2 / math.sqrt2),
height: 2 * (300 / 2 / math.sqrt2),
child: Material(
color: Colors.teal,
child: InkWell(
child: Image.network(
"https://raw.githubusercontent.com/flutter/website/master/examples/_animation/radial_hero_animation/images/chair-alpha.png"),
onTap: () {
Navigator.of(context).pop();
},
),
)),
),
),
),
),
)
],
),
),
));
}
}
正切方形计算
关键地方来了:
所有代码都看着没问题,Hero也使用的正常,但问题是为什么要在方形布局上面用圆形布局包裹呢?
我有办法了,我把圆形布局设置个背景,大家就容易看了:
效果图(1.3)
从效果图可以看到,其实是方形当中有一个正切正方形,
咋们在代码中使用SizedBox()设置了圆的直径为300dp
300 / 2 = 150 所以圆的半径就是150dp
先来解释这段代码吧:
width: 2 * (300 / 2 / math.sqrt2),
height: 2 * (300 / 2 / math.sqrt2),
300 / 2是圆的半径,这个mat.sqrt2是什么呢?
mat.sqrt2是2的平方根
通过数学公式 (半径/根号2)*2算出正切正方形的宽度
所以这里的宽和高就是正切正方形的宽度:
width: 2 * (300 / 2 / math.sqrt2),
height: 2 * (300 / 2 / math.sqrt2),
他其实就是2个圆背景之间的转换,跳转到大圆的时候,不显示大圆背景,而是使用正方形的背景,这样就有了从小圆到大正方形过度的效果!
页面跳转:
接下来给图片添加点击事件,完成两个页面之间的透明度动画跳转:
//水波纹点击事件
onTap: () {
Navigator.of(context).push(
initPageRouteBuilder(),
);
},
Route<Object> initPageRouteBuilder() {
return PageRouteBuilder(
pageBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation) {
return JumpHeroPage();
},
//打开新页面的时间
transitionDuration: Duration(seconds: 2),
//关闭页面的时间
reverseTransitionDuration: Duration(seconds: 1),
//打开页面的动画
transitionsBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return FadeTransition(
opacity:
new Tween<double>(begin: 0, end: 1).animate(
CurvedAnimation(
parent: animation,
curve: Curves.linear,
),
),
child: child,
);
},
);
}
这里的跳转和上一章:Flutter Hero动画(2.5)一模一样,只是跳转的页面不一样而已,不懂的朋友可以点进去康一康~
先来看看现在的效果图吧:
效果图(1.4):
走到这里没有完成的还有:
2个界面,一张小图圆形背景,一张用Card包裹的大图方形背景- 从小圆圆形页面跳转到大方形页面
大圆方形页面外层由Card包裹小圆跳转到大方页面透明度由0变化到1,大方形页面也如此- 大方形页面返回时,由方形变化到圆形
水波纹点击时效果
走到这里可以发现,大部分已经没有问题了,可是为什么跳转时,为什么要有椭圆形的动作呢?
返回时也一样,为什么先是正方形==>椭圆形==>圆形呢?
这里就涉及到Hero中的一个属性:
Hero(
createRectTween: (Rect begin, Rect end) {
return MaterialRectCenterArcTween(begin: begin, end: end);
},
tag:"",
)
只需要添加这行代码,即可没有跳转时的椭圆形转变;它是flutter里面的一个类,它就是用于完成从方形到圆形变化的一个辅助类
到现在,所有的都已经结束了,来看看最终效果吧:
总结:
本章使用了径向Hero动画,我其实也不知道为什么要叫径向,我也是在慕课网看老师写的,他的代码我是完全看不懂,就自己摸索的写了一下,效果是一样的,本篇中的Hero并没有对图片做什么,他是对图片后的背景,由小圆到大圆的变化,大圆中显示的是正切正方形,大圆也不给背景,只给正切正方形背景,这样转变的时候,就有了这样的效果.代码中我也没有封装,可读性还是挺高的,要有兴趣的朋友可以尝试的封装一下.哈哈哈,我太棒了,感觉自己今天是神~
下一章:Flutter 自定义AppBar,轮子Banner(2.7)
原创不易,您的点赞及评论是对我最大的支持,留下您的点赞吧~
下面是我的公众号,平时会发一些andorid和 flutter 的小知识等,主要用来记录工作开发中的一些小知识,有喜欢的朋友可以扫描二维码咋们互相进步~