• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Flutter开发(十五)Flutter动画基础

武飞扬头像
吴庆森
帮助1

1.哪些类型动画

2.添加动画

3.为动画添加监听器

4.AnimatedWidget 与 AnimatedBuilder

5.Hero动画

1.哪些类型动画

大概分为两类:基于 tween 和基于物理。

tween 动画就是补间动画,定义开始点和结束点、时间线和定义转化时间和速度的曲线。

基于物理的动画:就是模拟真实世界。比如扔个球,会做抛物线,然后弹了几下。

2.添加动画

几个常见类:

Animation : 动画库核心,生成指导动画的值。

CurvedAnimation : Animation 子类,将过程抽象为一个非线性曲线。

AnimationController : Animation 子类,管理 Animation。

Tween : 在正在执行动画的对象所使用的数据范围之间生成值。比如红到绿,它可以自动生成过程。

动画的几个状态方法:

forward()        启动动画

reverse({double from})        倒放动画

reset()        重置动画

stop({bool canceled = true})        停止动画

动画使用大概步骤:

① 创建 AnimationController ,指定动画时间;

② 创建 Tween ,传入区间大小变化,传入控制器 AnimationController ;

③ 添加动画变化监听器,类型是 double 类型,每回调一次就会用 setState() 刷新一次页面;

④ 添加动画状态监听器,来监听动画的状态:开始和停止等,利用 setState() 刷新页面;

⑤ 添加一个图片,动态设置它的大小;

示例代码如下,大概就是一个图标从宽高为0两秒内变成宽高为300的过程:

  1.  
    void main() {
  2.  
    runApp(MyApp());
  3.  
    }
  4.  
     
  5.  
    class MyApp extends StatefulWidget {
  6.  
    @override
  7.  
    _MyHomePageState createState() => _MyHomePageState();
  8.  
    }
  9.  
     
  10.  
    class _MyHomePageState extends State<MyApp>
  11.  
    with SingleTickerProviderStateMixin {
  12.  
    late Animation<double> animation;
  13.  
    late AnimationController controller;
  14.  
    //设置了一个初始状态。
  15.  
    late AnimationStatus animationStatus = AnimationStatus.reverse;
  16.  
    late double animationValue = 0;
  17.  
     
  18.  
    @override
  19.  
    void initState() {
  20.  
    super.initState();
  21.  
    // ① 创建 AnimationController ,指定动画时间;
  22.  
    // 其中 vsync: this 表示该动画被别的页面遮挡,防止消耗不必要的资源。
  23.  
    controller =
  24.  
    AnimationController(duration: const Duration(seconds: 2), vsync: this);
  25.  
    // ② 创建 Tween ,传入区间大小变化,传入控制器 AnimationController ;
  26.  
    animation = Tween<double>(begin: 0, end: 300).animate(controller)
  27.  
    // ③ 添加动画变化监听器,类型是 double 类型,每回调一次就会用 setState() 刷新一次页面;
  28.  
    ..addListener(() {
  29.  
    setState(() {
  30.  
    animationValue = animation.value;
  31.  
    });
  32.  
    })
  33.  
    // ④ 添加动画状态监听器,来监听动画的状态:开始和停止等,利用 setState() 刷新页面;
  34.  
    ..addStatusListener((AnimationStatus status) {
  35.  
    setState(() {
  36.  
    animationStatus = status;
  37.  
    });
  38.  
    });
  39.  
    }
  40.  
     
  41.  
    @override
  42.  
    Widget build(BuildContext context) {
  43.  
    return Container(
  44.  
    margin: EdgeInsets.only(top: 100),
  45.  
    child: Column(
  46.  
    children: [
  47.  
    //点击监听
  48.  
    GestureDetector(
  49.  
    onTap: () {
  50.  
    //重置动画
  51.  
    controller.reset();
  52.  
    //动画开始
  53.  
    controller.forward();
  54.  
    },
  55.  
    child: Text(
  56.  
    'Start',
  57.  
    textDirection: TextDirection.ltr,
  58.  
    ),
  59.  
    ),
  60.  
    Text('State:' animationStatus.toString(),
  61.  
    textDirection: TextDirection.ltr),
  62.  
    Text('Value:' animationValue.toString(),
  63.  
    textDirection: TextDirection.ltr),
  64.  
    // ⑤ 添加一个图片,动态设置它的大小;
  65.  
    Container(
  66.  
    height: animation.value,
  67.  
    width: animation.value,
  68.  
    child: FlutterLogo(),
  69.  
    )
  70.  
    ],
  71.  
    ));
  72.  
    }
  73.  
     
  74.  
    @override
  75.  
    void dispose() {
  76.  
    controller.dispose();
  77.  
    super.dispose();
  78.  
    }
  79.  
    }
学新通

3.为动画添加监听器

上面代码中已经添加了两个监听:

..addListener        动画的值发生变化被调用

..addStatusListener        动画状态发生变化被调用

4.AnimatedWidget 与 AnimatedBuilder

上面代码中,必须得添加动画的变化监听,然后不停调用 setState ,才能显示动画。AnimatedWidget 可以简化这一个操作,AnimatedWidget 很常用,它的作用就是简化动画。

简化完成的代码:

  1.  
    import 'package:flutter/material.dart';
  2.  
    import 'package:flutter/animation.dart';
  3.  
     
  4.  
    void main() {
  5.  
    runApp(MyApp());
  6.  
    }
  7.  
     
  8.  
    class MyApp extends StatefulWidget {
  9.  
    @override
  10.  
    _MyHomePageState createState() => _MyHomePageState();
  11.  
    }
  12.  
     
  13.  
    class _MyHomePageState extends State<MyApp>
  14.  
    with SingleTickerProviderStateMixin {
  15.  
    late Animation<double> animation;
  16.  
    late AnimationController controller;
  17.  
     
  18.  
    @override
  19.  
    void initState() {
  20.  
    super.initState();
  21.  
    // ① 创建 AnimationController ,指定动画时间; 其中 vsync: this 表示该动画被别的页面遮挡,防止消耗不必要的资源。
  22.  
    controller =
  23.  
    AnimationController(duration: const Duration(seconds: 2), vsync: this);
  24.  
    // ② 创建 Tween ,传入区间大小变化,传入控制器 AnimationController ;
  25.  
    animation = Tween<double>(begin: 0, end: 300).animate(controller);
  26.  
    controller.forward();
  27.  
    }
  28.  
     
  29.  
    @override
  30.  
    Widget build(BuildContext context) {
  31.  
    return new AnimatedLogo(animation: animation);
  32.  
    }
  33.  
     
  34.  
    @override
  35.  
    void dispose() {
  36.  
    controller.dispose();
  37.  
    super.dispose();
  38.  
    }
  39.  
    }
  40.  
     
  41.  
    class AnimatedLogo extends AnimatedWidget {
  42.  
    AnimatedLogo({Key? key, required Animation<double> animation})
  43.  
    : super(key: key, listenable: animation);
  44.  
     
  45.  
    @override
  46.  
    Widget build(BuildContext context) {
  47.  
    final Animation<double> animation = listenable as Animation<double>;
  48.  
    return new Center(
  49.  
    child: new Container(
  50.  
    margin: new EdgeInsets.symmetric(vertical: 10.0),
  51.  
    height: animation.value,
  52.  
    width: animation.value,
  53.  
    child: new FlutterLogo(),
  54.  
    )
  55.  
    );
  56.  
    }
  57.  
    }
学新通

AnimatedBuilder 是用于构建动画的通用 widget,作用是拆分动画,可以将动画和 widget 进行分离。

将上面的动画拆分为三块:显示图片,定义动画,渲染动画效果。

示例代码:

  1.  
    void main() {
  2.  
    runApp(MyApp());
  3.  
    }
  4.  
     
  5.  
    class MyApp extends StatefulWidget {
  6.  
    @override
  7.  
    _MyHomePageState createState() => _MyHomePageState();
  8.  
    }
  9.  
     
  10.  
    class _MyHomePageState extends State<MyApp>
  11.  
    with SingleTickerProviderStateMixin {
  12.  
    late Animation<double> animation;
  13.  
    late AnimationController controller;
  14.  
     
  15.  
    @override
  16.  
    void initState() {
  17.  
    super.initState();
  18.  
    // ① 创建 AnimationController ,指定动画时间; 其中 vsync: this 表示该动画被别的页面遮挡,防止消耗不必要的资源。
  19.  
    controller =
  20.  
    AnimationController(duration: const Duration(seconds: 2), vsync: this);
  21.  
    // ② 创建 Tween ,传入区间大小变化,传入控制器 AnimationController ;
  22.  
    animation = Tween<double>(begin: 0, end: 300).animate(controller);
  23.  
    controller.forward();
  24.  
    }
  25.  
     
  26.  
    @override
  27.  
    Widget build(BuildContext context) {
  28.  
    return GrowTransition(child: LogoWidget(),animation: animation);
  29.  
    }
  30.  
     
  31.  
    @override
  32.  
    void dispose() {
  33.  
    controller.dispose();
  34.  
    super.dispose();
  35.  
    }
  36.  
    }
  37.  
     
  38.  
    class GrowTransition extends StatelessWidget {
  39.  
    GrowTransition({required this.child, required this.animation});
  40.  
     
  41.  
    final Widget child;
  42.  
    final Animation<double> animation;
  43.  
     
  44.  
    @override
  45.  
    Widget build(BuildContext context){
  46.  
    return Center(
  47.  
    child: AnimatedBuilder(
  48.  
    animation: animation,
  49.  
    builder: (context, child) {
  50.  
    return Container(
  51.  
    height: animation.value,
  52.  
    width: animation.value,
  53.  
    child: child,
  54.  
    );
  55.  
    },
  56.  
    child: child,
  57.  
    ),
  58.  
    );
  59.  
    }
  60.  
    }
  61.  
     
  62.  
    class LogoWidget extends StatelessWidget {
  63.  
    @override
  64.  
    Widget build(BuildContext context) {
  65.  
    return new Container(
  66.  
    margin: EdgeInsets.symmetric(vertical: 10),
  67.  
    child: FlutterLogo(),
  68.  
    );
  69.  
    }
  70.  
    }
学新通

5.Hero动画

从第一个页面跳转到第二个页面,并且两个页面都有这个图标,可以用这个动画来实现。实现一个飞入的感觉。

效果可以看官网:Flutter Hero动画 - Flutter中文网

示例代码,下面代码我把 timeDilation = 5.0; 注释了,加上这个报错,不知道为什么,报错信息是

  1.  
    Error: Setter not found: 'timeDilation'.
  2.  
    timeDilation = 5.0;

学新通

有知道的小伙伴告诉我一下原因吧~ 

下面是完整代码:

  1.  
     
  2.  
    import 'package:flutter/material.dart';
  3.  
    import 'package:flutter/scheduler.dart' show timeDilation;
  4.  
     
  5.  
     
  6.  
    void main() {
  7.  
    runApp(MaterialApp(home: HeroAnimation()));
  8.  
    }
  9.  
     
  10.  
    class PhotoHero extends StatelessWidget {
  11.  
    const PhotoHero({ Key? key,required this.photo,required this.onTap, required this.width }) : super(key: key);
  12.  
     
  13.  
    final String photo;
  14.  
    final VoidCallback onTap;
  15.  
    final double width;
  16.  
     
  17.  
    Widget build(BuildContext context) {
  18.  
    return new SizedBox(
  19.  
    width: width,
  20.  
    child: new Hero(
  21.  
    tag: photo,
  22.  
    child: new Material(
  23.  
    color: Colors.transparent,
  24.  
    child: new InkWell(
  25.  
    onTap: onTap,
  26.  
    child: new Image.asset(
  27.  
    photo,
  28.  
    fit: BoxFit.contain,
  29.  
    ),
  30.  
    ),
  31.  
    ),
  32.  
    ),
  33.  
    );
  34.  
    }
  35.  
    }
  36.  
     
  37.  
    class HeroAnimation extends StatelessWidget {
  38.  
    @override
  39.  
    Widget build(BuildContext context) {
  40.  
    // timeDilation = 5.0;
  41.  
     
  42.  
    return new Scaffold(
  43.  
    appBar: new AppBar(
  44.  
    title: const Text('Basic Hero Animation'),
  45.  
    ),
  46.  
    body: new Center(
  47.  
    child: new PhotoHero(
  48.  
    photo: 'assets/images/my_icon.jpg',
  49.  
    width: 300.0,
  50.  
    onTap: () {
  51.  
    Navigator.of(context).push(new MaterialPageRoute<void>(
  52.  
    builder: (BuildContext context) {
  53.  
    return new Scaffold(
  54.  
    appBar: new AppBar(
  55.  
    title: const Text('Flippers Page'),
  56.  
    ),
  57.  
    body: new Container(
  58.  
    // The blue background emphasizes that it's a new route.
  59.  
    color: Colors.lightBlueAccent,
  60.  
    padding: const EdgeInsets.all(16.0),
  61.  
    alignment: Alignment.topLeft,
  62.  
    child: new PhotoHero(
  63.  
    photo: 'assets/images/my_icon.jpg',
  64.  
    width: 100.0,
  65.  
    onTap: () {
  66.  
    Navigator.of(context).pop();
  67.  
    },
  68.  
    ),
  69.  
    ),
  70.  
    );
  71.  
    }
  72.  
    ));
  73.  
    },
  74.  
    ),
  75.  
    ),
  76.  
    );
  77.  
    }
  78.  
    }
学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfkekgg
系列文章
更多 icon
同类精品
更多 icon
继续加载