Flutter Hero动画(2.6)

今天给大家带来的是径向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 Hero动画(2.5)

下一章:Flutter 自定义AppBar,轮子Banner(2.7)

原创不易,您的点赞及评论是对我最大的支持,留下您的点赞吧~



下面是我的公众号,平时会发一些andoridflutter 的小知识等,主要用来记录工作开发中的一些小知识,有喜欢的朋友可以扫描二维码咋们互相进步~

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

s10g

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值