Flutter(十六)——Hero动画

简介: Flutter(十六)——Hero动画

前言


在前面实践组件的开发中,我们做了一个登录的界面,里面有一个组件Hero,不知道大家是否记得?当时没有展开来说,是因为它属于动画的内容,本文就要重点讲解Hero动画。

做过Java开发Android的程序员应该都清楚,Shared Element Transition可以让Activity或Fragment做出流畅的动画,同样,在Flutter开发中,Hero动画也能实现类似的效果。简单来说,Hero的作用就是在路由之间做出流畅的转场动画。


基本用法


Hero组件的用法是需要同时定义源组件和目标组件,其中源组件和目标组件被Hero包裹在需要动画控制的组件外面,如果有一方不指定,在有些情况下,界面就会卡死,我们先来看看它的基本用法,首先是main.dart代码:

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("我是第一个界面"),
      ),
      body: Center(
        child: GestureDetector(
          child: Hero(
            tag: "tag1",
            child: FlutterLogo(
              size: 200,
            ),
          ),
          onTap: () {
            Navigator.push(context, MaterialPageRoute(builder: (BuildContext context)=>CustomFlutterLogoPage()));
          },
        ),
      ),
    );
  }
}


代码很简单,就是监听点击事件ontap,hero包裹FlutterLogo组件,然后点击跳转到第二个界面。接着我们再来看看第二个页面CustomFlutterLogo.dart的代码:

import 'package:flutter/material.dart';
class CustomFlutterLogoPage extends StatefulWidget {
  CustomFlutterLogoPage({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _CustomFlutterLogoState createState() => _CustomFlutterLogoState();
}
class _CustomFlutterLogoState extends State<CustomFlutterLogoPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("我是第二个页面"),),
      body: Center(
        child: Hero(
          tag: "tag2",
          child: CustomFlutterLogo(
            size: 400,
            name: "我是第二个页面",
          ),
        ),
      ),
    );
  }
}
class CustomFlutterLogo extends StatelessWidget{
  final double size;
  final String name;
  CustomFlutterLogo({this.size=200.0,this.name});
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: FlutterLogo(
          size: this.size,
        ),
      ),
    );
  }
}


这段代码也很简单,就是常用的组件,只是在外层套了一层Hero动画组件,不过这里有一点我们需要注意,hero里面有一个tag属性,必须写上,不然会报错,不信的读者,可以删除后运行试试。


实现原理


我们基本已经掌握了Hero路由跳转动画的用法,但我们不能只看表面,不明其原理,因为后面讲解的动画也会涉及到这些知识,所以我们必须掌握。


Hero动画,它的整个运动过程分为3个步骤,即动画开始(t=0.0),动画进行中,动画结束(t=1.0),下面是Hero动画运动示意图:

如上图所示,两个路由之间还有一个Overlay层。在动画开始时,Flutter会计算出Hero的位置并复制一份,然后绘制到Overlay层上。复制的Hero和源Hero的大小是一致的,并且该Hero是在所有路由之上。在动画实现的过程中,Flutter会逐渐把源Hero移除屏幕。在动画进行中Flutter是依靠Tween来实现,通过createRectTween属性把Tween传给Hero。Hero内部默认使用MeterialRectArcTween的曲线路径进行移动动画的操作。在动画结束时,Flutter将Overlay中的Hero移除,且完成了Hero在目标路由上的显示,这时Overlay是空白的。


Hero中所有变换都是通过HeroController来实现的,HeroController是在MeterialApp中通过initState和didUpdateWidget方法来完成初始化的,源码如下所示:

class _MaterialAppState extends State<MaterialApp>{
  HeroController heroController;
  @override
  void initState(){
  super.initState();
  _heroController=HeroController(createRectTween:_createRectTween);
  _updateNavigator();
  }
  @override
  void didUpdateWidget(MaterialApp oldWidget){
  super.didUpdateWidget(oldWidget);
  if(widget.navigatorKey!=oldWidget.navigatorKey){
    _heroController=HeroController(createRectTween:_createRectTween);
  }
  _updateNavigator();
  }
  RectTween _createRectTween(Rect begin,Rect end){
  return MaterialRectArcTween(begin:begin,end:end);
  }
}


在初始化HeroController时,Flutter携带了一个参数,就是_createRectTween,该参数返回的默认项就是MaterialRectArcTween。Flutter源码里还为我们实现了第二种RectTween返回值,即MaterialRectCenterArcTween。由此可见,可以对createRectTween进行自定义。我们再看看HeroController的具体内容,代码如下:

@override
void didPush(Route<dynamic> route,Route<dynamic> previousRoute){
  assert(navigator!=null);
  assert(route!=null);
  _maybeStartHeroTransition(previousRoute,route,HeroFlightDirection.push,false);
}
@override
void didPop(Route<dynamic> route,Route<dynamic> previousRoute){
  assert(navigator!=null);
  assert(route!=null);
  _maybeStartHeroTransition(route,previousRoute,HeroFlightDirection.pop,false);
}


HeroController其实继承的是NavigatorObserver。在路由操作的didPush和didPop回调方法里,可以调用_maybeStartHeroTransition,并通过WidgetsBinding把源路由,目标路由,HeroController关联起来。在使用didPush和didPop回调时,通过调用_startHeroTransition方法让Hero动起来,只不过前者是正向的,后者是逆向的。

相关文章
动画控制器在 Flutter 中的工作原理
【10月更文挑战第18天】总的来说,动画控制器 `AnimationController` 在 Flutter 中起着关键的作用,它通过控制动画的数值、速度、节奏和状态,实现了丰富多彩的动画效果。理解它的工作原理对于我们在 Flutter 中创建各种精彩的动画是非常重要的。
275 60
|
开发工具 UED 容器
Flutter&鸿蒙next 实现长按录音按钮及动画特效
本文介绍了如何在 Flutter 中实现一个带有动画效果的长按录音按钮。通过使用 `GestureDetector` 监听长按手势,结合 `AnimatedContainer` 和 `AnimationController` 实现按钮的动画效果,以及 `flutter_sound` 插件完成录音功能。文章详细讲解了功能需求、实现思路和代码实现,帮助读者逐步掌握这一实用功能的开发方法。
464 5
|
前端开发 开发者
深入探索 Flutter 鸿蒙版的画笔使用与高级自定义动画
本文深入探讨了 Flutter 中的绘图功能,重点介绍了 CustomPainter 和 Canvas 的使用方法。通过示例代码,详细讲解了如何绘制自定义图形、设置 Paint 对象的属性以及实现高级自定义动画。内容涵盖基本绘图、动画基础、渐变动画和路径动画,帮助读者掌握 Flutter 绘图与动画的核心技巧。
272 1
|
前端开发
Flutter快速实现自定义折线图,支持数据改变过渡动画
Flutter快速实现自定义折线图,支持数据改变过渡动画
351 4
Flutter快速实现自定义折线图,支持数据改变过渡动画
flutter:动画&状态管理 (十三)
本文档介绍了Flutter中`animatedList`的使用方法和状态管理的示例。`animatedList`用于创建带有动画效果的列表,示例代码展示了如何添加、删除列表项,并执行相应的动画效果。状态管理部分通过一个简单的点击切换颜色的示例,演示了如何在Flutter中管理组件的状态。
199 0
Flutter-加载中动画
Flutter-加载中动画
148 0
Flutter-自定义表情雨下落动画
Flutter-自定义表情雨下落动画
133 0
Flutter-数字切换动画
Flutter-数字切换动画
137 0
|
开发者
Flutter 动画学习
Flutter 动画学习