美文网首页Flutter圈子Flutter 入门与实战
页面切换转场动画,英雄救场更有趣!

页面切换转场动画,英雄救场更有趣!

作者: 岛上码农 | 来源:发表于2022-05-27 20:26 被阅读0次

    前言

    写了一篇基础的性能优化的内容,继续我们的动画相关的介绍。今天的主角是英雄 —— Hero 组件。Hero 组件非常适合从列表、概览页切换到详情页转场动画场合。因为可以将两个页面的组件串起来动画,体验上会觉得整个操作的连贯性非常好。下面是我们这篇要做的一个效果。


    Hero转场动画效果.gif

    Hero 动画过程

    Hero 本质是是在不同的路由页面做了一个中转层,然后通过动画完成过渡,下面用4张图是官方演示的过程。

    • 动画开始前,会准备一个空的遮罩层(Overlay)。此时目标路由页面还没生成。


      动画开始前.jpg
    • t = 0.0,即动画开始时,源页面已经从屏幕消失,遮罩层出现在屏幕上,此时目标路由页面已经构建好,并且在遮罩层下方不可见。但此时 Flutter 渲染引擎已经计算出从遮罩层到目标路由页面的动画路径。


      动画就绪.jpg
    • 动画过程中,英雄飞起来,逐步飞到目标页面。使用的是Tween<Rect>方式更改外形和位置,默认是使用 MaterialRectArcTween 对象完成动画。

      飞行过程.jpg
    • 动画结束:遮罩层消失,只剩下目标路由页面。而源页面恢复到它对应的路由状态(以便返回时使用逆向的动画)。


      动画结束.jpg

    Hero 基础示例

    下面来看我们本篇动画效果的实现。对于 Hero 最简单的应用,就是前后两个路由页面的 Hero 组件使用相同的 tag 标识,然后所有动画都交给 Hero 来完成了 —— 果然是超级英雄,啥都不用我们管!当然,为了用户体验,前后两个页面的组件最好是具有相同的内容(比如图片),然后如果组件树结构是一致的话效果更好。

    我们这个示例的第一个页面就是两张小尺寸的图片,这里的关键是 Hero 组件的 tag 标签,两张图片使用了不同的 tag这是因为同一个页面的多个 Hero 不能共用 tag

    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: Text('Hero 基础动画'),
          brightness: Brightness.dark,
        ),
        body: Center(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Hero(
                tag: 'beauty1',
                child: RoundImage(
                  onTap: () {
                    Navigator.of(context).push(
                      MaterialPageRoute(
                        builder: (context) => HeroDetail(
                          tag: 'beauty1',
                          assetImageName: 'images/beauty.jpeg',
                        ),
                      ),
                    );
                  },
                  assetImageName: 'images/beauty.jpeg',
                  imageSize: 80.0,
                ),
              ),
              // 省略图片2
            ],
          ),
        ),
      );
    }
    

    详情页面只有一个居中的图片,也是用的 Hero 组件。只是为了和源页面一致,这里的 tag,图片资源都是由源页面传递进来。

    class HeroDetail extends StatelessWidget {
      final String tag;
      final String assetImageName;
      const HeroDetail({Key? key, required this.tag, required this.assetImageName})
          : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Hero 基础动画详情'),
            brightness: Brightness.dark,
          ),
          body: Center(
            child: SizedBox(
              width: 200,
              height: 200,
              child: Hero(
                tag: this.tag,
                child: RoundImage(
                  onTap: () {
                    Navigator.of(context).pop();
                  },
                  assetImageName: this.assetImageName,
                  imageSize: 200.0,
                ),
              ),
            ),
          ),
        );
      }
    }
    

    这样就完成了我们前面的转场动画效果,源码已上传至:动画相关源码。怎么样?有了 Hero之后,是不是感觉英雄救场一样,让你的转场轻松多了!

    总结

    本篇介绍了 Hero 动画的基本过程和基础示例。借助 Hero,对于我们很多场景可以让转场效果更好,比如说从商品列表切换到商品详情,从资讯列表到资讯详情。都可以给用户带来更好的体验。

    相关文章

      网友评论

        本文标题:页面切换转场动画,英雄救场更有趣!

        本文链接:https://www.haomeiwen.com/subject/xpdvprtx.html