首页 > 其他分享 >Flutter 陈航 22-动画 Animation Hero

Flutter 陈航 22-动画 Animation Hero

时间:2023-01-08 16:02:24浏览次数:53  
标签:动画 Hero 22 陈航 controller Animation AnimatedWidget context animation

本文地址


目录

目录

22 | 如何构造炫酷的动画效果?

原文

Flutter 完全接管了渲染层,除了静态的页面布局之外,对组件动画的支持自然也不在话下。

Animation

  • Animation:根据预定规则,在单位时间内持续输出动画的当前状态
  • AnimationController:用于管理 Animation,可用来设置动画的时长、启动/暂停、反转动画等
  • Listener:是 Animation 的回调函数,用来监听动画的进度变化,进而根据当前值重新渲染组件

Animation 仅提供动画的数据,而不负责动画的渲染,因此我们还需要监听动画执行进度,并在回调中使用 setState 强制刷新界面才能看到动画效果。

案例

class HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
  double _width = 50;
  late AnimationController controller;

  @override
  void initState() {
    Duration duration = const Duration(milliseconds: 2000); // 动画周期为 2000 毫秒
    controller = AnimationController(vsync: this, duration: duration); // vsync 用于防止出现不可见动画

    Animation<double> animation = Tween(begin: 50.0, end: 300.0).animate(controller); // 从 50 到 300 线性变化的动画
    animation.addListener(() {
      //flog("进度回调 value = ${animation.value}");
      setState(() => _width = animation.value);
    });
    animation.addStatusListener((status) => flog("status = ${status.name}"));
    super.initState();
  }

  void _onPressed() {
    flog("duration = ${controller.duration?.inMilliseconds}, status = ${controller.status}, "
        "velocity = ${controller.velocity.toStringAsExponential(1)}, animationBehavior = ${controller.animationBehavior}, "
        "animating = ${controller.isAnimating}, complete = ${controller.isCompleted}, dismiss = ${controller.isDismissed}");
    controller.reset(); // 重置到默认状态
    controller.forward().then((value) => flog("动画执行完毕")); //启动动画
  }

  @override
  Widget build(BuildContext context) => Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: Image.asset("assets/images/monkey.jpg", width: _width),
      floatingActionButton: FloatingActionButton(onPressed: _onPressed));

  @override
  void dispose() {
    controller.dispose(); // 释放资源
    super.dispose();
  }
}

上面在创建 AnimationController 的时候,设置了一个 vsync 属性,设置后会把动画绑定到一个 Widget,当 Widget 不显示时,动画将会暂停,当 Widget 再次显示时,动画会重新恢复执行,这样就可以避免动画组件不可见时消耗资源。

非线性曲线动画

Tween 默认是线性变化的,通过创建 CurvedAnimation 可以实现非线性曲线动画。Curves 提供了很多常用的曲线,比如震荡曲线 elasticOut

CurvedAnimation curve = CurvedAnimation(parent: controller, curve: Curves.elasticOut); // 震荡曲线
Animation<double> animation = Tween(begin: 50.0, end: 300.0).animate(curve);

心跳效果

如果想让动画像心跳一样执行,有两个办法:

  • 使用 controller.repeat(reverse: true) 启动动画,让动画来回重复执行
  • 监听动画状态,在动画结束时,反向执行;在动画反向执行完毕时,重新启动执行
animation.addStatusListener((status) {
  if (status == AnimationStatus.completed) {
    controller.reverse(); // 动画结束时反向执行
  } else if (status == AnimationStatus.dismissed) {
    controller.forward(); // 动画反向执行完毕时,重新执行
  }
});
controller.forward();

简化动画代码

Flutter 提供了两个类来简化动画代码,即 AnimatedWidget 与 AnimatedBuilder。

AnimatedWidget

AnimatedWidget 会将 Animation 的状态与其子 Widget 的视觉样式绑定,因此,我们只需把 Animation 对象传入 AnimatedWidget 即可,而不用再通过监听动画的执行进度刷新 UI 了。

class AnimatedImage extends AnimatedWidget {
  final Animation<double> animation;

  const AnimatedImage(this.animation, {super.key}) : super(listenable: animation);

  @override
  Widget build(BuildContext context) => Image.asset("assets/images/monkey.jpg", width: animation.value);
}

AnimatedBuilder

与 AnimatedWidget 类似,AnimatedBuilder 也会自动监听 Animation 对象的变化,并根据需要将该控件树标记为 dirty 以自动刷新 UI。

AnimatedBuilder 也是继承自 AnimatedWidget 的

AnimatedBuilder(
  animation: animation, // 自动监听 Animation 的变化,并通过 builder 重新构建 Widget
  builder: (context, child) => Image.asset("assets/images/monkey.jpg", width: animation.value),
)

Hero 动画

共享元素变换 Shared Element Transition:在两个页面的共享元素之间,做出流畅的页面切换效果

Android 原生提供了对这种动画效果的支持,通过几行代码,就可以实现在两个 Activity 共享的组件之间做出流畅的转场动画。Flutter 也有类似的概念,即 Hero 控件。

为了实现共享元素变换,我们需要将这两个组件分别用 Hero 包裹,并同时为它们设置相同的 tag

class HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
  void _onPressed() {
    Route<HomePage> route = MaterialPageRoute(
      builder: (context) => const HomePage(title: "页面2"),
      settings: const RouteSettings(arguments: 300.0),
    );
    Navigator.push(context, route);
  }

  @override
  Widget build(BuildContext context) => Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: Hero(
        tag: 'monkey', // 设置共享 tag
        child: Image.asset("assets/images/monkey.jpg", width: getArguments(context)),
      ),
      floatingActionButton: FloatingActionButton(onPressed: _onPressed));

  double getArguments(BuildContext context) {
    Object? arguments = ModalRoute.of(context)?.settings.arguments;
    return arguments is double ? arguments : 50.0;
  }
}

总结

在 Flutter 中,动画的状态与渲染是分离的。我们通过 Animation 生成动画曲线,使用 AnimationController 控制动画时间、启动动画。而动画的渲染,则需要 addListener 获取动画进度后,主动刷新才能实现动画的更新。

为了简化这一步骤,Flutter 提供了 AnimatedWidgetAnimatedBuilder 这两个组件,省去了状态监听和 UI 刷新的工作。而对于跨页面动画,Flutter 提供了 Hero 组件,只要两个组件有同样的 tag,就能实现元素跨页面过渡的转场效果。

建议尽量使用 AnimatedWidget 或 AnimatedBuilder 来缩小受动画影响的组件范围,只重绘需要做动画的组件。

2023-1-8

标签:动画,Hero,22,陈航,controller,Animation,AnimatedWidget,context,animation
From: https://www.cnblogs.com/baiqiantao/p/17034775.html

相关文章

  • Good Bye 2022: 2023 is NEAR
    中文题面中文题解A.KoxiaandWhiteboards因为必须要对\(a_i\)做替换,那么把\(a_i\)中最小的替换掉是最优的#include<bits/stdc++.h>#defineintlonglongusingnam......
  • 牛客2022跨年场
    B.分赃首先统计只有一个的数字个数,如果是偶数就平均分给两个人,然后把剩下的数字全部分给任意一个人。如果是奇数个,就看时候有数字的数量大于三,如果有,就把这个数字的其中......
  • One Bamboo Contest Round #11(Clone from 2022 ICPC Manila)
    马尼拉区域赛题目出得还是不错的,只是感觉大多数参赛队伍的水平不太行,我们这样的队伍居然能苟到铜牌A.AnEasyCalculusProblem签到#include<bits/stdc++.h>#define......
  • Stack Overflow Developer Survey 2022 All In One
    StackOverflowDeveloperSurvey2022AllInOnehttps://survey.stackoverflow.co/2022Rust(......
  • 最完美WIN11_Pro_22H2.22623.1095软件选装纯净版VIP38.4
    【系统简介】=============================================================1.本次更新母盘来UUP_WIN11_Pro_22H2.22623.1095。进一步优化调整。2.不支持更新,更新后精简版......
  • 2022年中小企业数字化转型路径报告(附下载链接)
    大家好,我是文文,今天给大家分享一份干货报告《2022中小企业数字化转型路径报告.pdf》。关注数字化转型的伙伴别错过了!到小程序省时查报告中搜索“数字化”、“转型”、“中台......
  • 2022朝花夕拾-持续快速成长
    ​​2022年又过去了,学业繁忙好久没和大家聊天了。​​2020年终总结2020朝花夕拾-不务正业的大学生做了什么比赛?​​和​​2021年终总结2021朝花夕拾-我在校搞副业实现经济......
  • 【小5聊】回看2022,展望2023,分享我的年度总结和感想,在一个行业十年,坚持下去你就是这个
     2022年,已成为过去!2023年,TA已悄然而至!非常感谢提供的技术平台,很早就关注了C站,11年的时候,当时用的是163邮箱注册的账号,也是主要用来找资料看文章。18年的时候,由于旧账号早就......
  • Flutter 陈航 21-路由 导航 Route Navigator 页面参数
    本文地址目录目录目录21|路由与导航,实现页面切换路由管理基本路由命名路由路由表routes页面PageNavigator.pushNamed页面参数启动参数返回参数总结21|路由与导航......
  • 【2022-12-28】连岳摘抄
    23:59中国人已经进入长寿社会,百岁老人比比皆是,而且比例将越来越高。很多人退休之时,人生刚走完一半。后面这半生如何安排,就显得非常重要。退休后不做点事,闲得发慌,既是巨大......