美文网首页
(Flutter)交错动画【译】

(Flutter)交错动画【译】

作者: 文vane | 来源:发表于2018-10-11 09:36 被阅读0次

    交错动画

    你将学习到什么:

    • 交错动画由序列或重叠的动画组成。
    • 要创建交错动画,使用多个动画对象。
    • 一个AnimationController控制所有动画。
    • 每个动画对象在间隔期间指定动画。
    • 对于要设置动画的每个属性,请创建一个Tween。

    Terminology: 如果补间或补间的概念对您来说是新的,请参阅Flutter教程中的动画

    交错的动画是一个直截了当的概念:视觉变化发生在一系列操作中,而不是一次性发生。 动画可能是纯粹顺序的,在下一个动画之后会发生一次更改,或者可能部分或完全重叠。 它也可能有间隙,没有发生变化。

    本指南介绍了如何在Flutter中构建交错动画。

    Examples

    本指南介绍了basic_staggered_animation示例。您还可以参考更复杂的示例staggered_pic_selection。
    basic_staggered_animation

    显示单个窗口小部件的一系列连续和重叠动画。 点击屏幕会开始一个动画,可以改变不透明度,大小,形状,颜色和填充。

    staggered_pic_selection

    显示从以三种尺寸之一显示的图像列表中删除图像。此示例使用两个动画控制器: 一个用于图像选择/取消选择,另一个用于图像删除。 选择/取消选择动画是错开的。 (要查看此效果,您可能需要增加timeDilation 值。) 选择一个最大的图像,它会缩小,因为它在蓝色圆圈内显示一个复选标记。 接下来,选择一个最小的图像,当复选标记消失时,大图像会扩展。 在大图像完成展开之前,小图像会缩小以显示其复选标记。 这种交错行为类似于您在Google相册中看到的行为。

    以下视频演示了basic_staggered_animation执行的动画:


    StaggerDemo.gif

    在视频中,您会看到单个小部件的以下动画,该小部件以带有略微圆角的边框蓝色方块开始。 该方块按以下顺序运行更改:

    1. 淡入
    2. 扩大
    3. 向上移动时变得更高
    4. 转变为有边界的圆圈
    5. 将颜色更改为橙​​色

    向前跑之后,动画反向运行。

    Flutter新手?
    本页假定您知道如何使用Flutter的小部件创建布局。 有关更多信息,请参阅在Flutter中构建布局.

    交错动画的基本结构

    重点是什么?

    • 所有动画都由同一个AnimationController驱动。
    • 无论动画实时持续多长时间,控制器的值必须介于0.0和1.0之间。
    • 每个动画的间隔介于0.0和1.0之间。
    • 对于在间隔中设置动画的每个属性,请创建一个Tween。 Tween指定该属性的开始值和结束值。
    • Tween生成一个由控制器管理的Animation对象。

    下图显示了basic_staggered_animation示例中使用的间隔。 您可能会注意到以下特征:

    • 不透明度在时间轴的前10%期间发生变化。
    • 不透明度的变化与宽度的变化之间存在微小的差距。
    • 在最后25%的时间线中没有任何动画。
    • 增加填充使小部件看起来向上。
    • 将边框半径增加到0.5,将带圆角的方形转换为圆形。
    • 填充和边界半径变化发生在相同的精确间隔期间,但它们不必。
    StaggeredAnimationIntervals.png

    要设置动画:

    • 创建一个管理所有动画的AnimationController。
    • 为每个动画属性创建一个Tween。
      • Tween定义了一系列值。
      • Tween的animate方法需要parent控制器,并为该属性生成一个Animation。
    • 在动画curve属性上指定间隔。

    当控制动画的值更改时,新动画的值会更改,从而触发UI更新。

    以下代码为width属性创建补间。 它构建一个CurvedAnimation ,指定一个缓和的曲线。 有关其他可用的预定义动画曲线,请参阅曲线

    width = Tween<double>(
      begin: 50.0,
      end: 150.0,
    ).animate(
      CurvedAnimation(
        parent: controller,
        curve: Interval(
          0.125, 0.250,
          curve: Curves.ease,
        ),
      ),
    ),
    

    beginend 的值不必是双倍的。下面的代码使用BorderRadius.circular()borderRadius属性(控制方块角的圆度)构建补间。

    borderRadius = BorderRadiusTween(
      begin: BorderRadius.circular(4.0),
      end: BorderRadius.circular(75.0),
    ).animate(
      CurvedAnimation(
        parent: controller,
        curve: Interval(
          0.375, 0.500,
          curve: Curves.ease,
        ),
      ),
    ),
    

    完成交错的动画

    与所有交互式小部件一样,完整的动画由小部件对组成:无状态小部件和有状态小部件。

    无状态窗口小部件指定补间,定义Animation对象,并提供build()函数,负责构建窗口小部件树的动画部分。

    有状态小部件创建控制器,播放动画,并构建小部件树的非动画部分。 在屏幕中的任何位置检测到点击时,动画开始。

    basic_staggered_animation’s main.dart的完整代码

    无状态小部件:StaggerAnimation

    在无状态小部件StaggerAnimation中, build()函数实例化一个AnimatedBuilder - 一个用于构建动画的通用小部件。 AnimatedBuilder构建一个小部件并使用Tweens的当前值配置它。 该示例创建一个名为_buildAnimation()的函数(执行实际的UI更新),并将其分配给其builder属性。 AnimatedBuilder监听来自动画控制器的通知,在值发生变化时将小部件树标记为脏。 对于动画的每个刻度,值都会更新,从而调用_buildAnimation()

    class StaggerAnimation extends StatelessWidget {
      StaggerAnimation({ Key key, this.controller }) :
    
        // Each animation defined here transforms its value during the subset
        // of the controller's duration defined by the animation's interval.
        // For example the opacity animation transforms its value during
        // the first 10% of the controller's duration.
    
        opacity = Tween<double>(
          begin: 0.0,
          end: 1.0,
        ).animate(
          CurvedAnimation(
            parent: controller,
            curve: Interval(
              0.0, 0.100,
              curve: Curves.ease,
            ),
          ),
        ),
    
        // ... Other tween definitions ...
    
        super(key: key);
    
      final Animation<double> controller;
      final Animation<double> opacity;
      final Animation<double> width;
      final Animation<double> height;
      final Animation<EdgeInsets> padding;
      final Animation<BorderRadius> borderRadius;
      final Animation<Color> color;
    
      // This function is called each time the controller "ticks" a new frame.
      // When it runs, all of the animation's values will have been
      // updated to reflect the controller's current value.
      Widget _buildAnimation(BuildContext context, Widget child) {
        return Container(
          padding: padding.value,
          alignment: Alignment.bottomCenter,
          child: Opacity(
            opacity: opacity.value,
            child: Container(
              width: width.value,
              height: height.value,
              decoration: BoxDecoration(
                color: color.value,
                border: Border.all(
                  color: Colors.indigo[300],
                  width: 3.0,
                ),
                borderRadius: borderRadius.value,
              ),
            ),
          ),
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return AnimatedBuilder(
          builder: _buildAnimation,
          animation: controller,
        );
      }
    }
    

    有状态小部件:StaggerDemo

    有状态小部件StaggerDemo创建了AnimationController(规定他们的对象),指定持续时间为2000毫秒。 它播放动画,并构建小部件树的非动画部分。 在屏幕中检测到点击时动画开始。 动画向前,然后向后。

    class StaggerDemo extends StatefulWidget {
      @override
      _StaggerDemoState createState() => _StaggerDemoState();
    }
    
    class _StaggerDemoState extends State<StaggerDemo> with TickerProviderStateMixin {
      AnimationController _controller;
    
      @override
      void initState() {
        super.initState();
    
        _controller = AnimationController(
          duration: const Duration(milliseconds: 2000),
          vsync: this
        );
      }
    
      // ...Boilerplate...
    
      Future<Null> _playAnimation() async {
        try {
          await _controller.forward().orCancel;
          await _controller.reverse().orCancel;
        } on TickerCanceled {
          // the animation got canceled, probably because we were disposed
        }
      }
    
      @override
      Widget build(BuildContext context) {
        timeDilation = 10.0; // 1.0 is normal animation speed.
        return Scaffold(
          appBar: AppBar(
            title: const Text('Staggered Animation'),
          ),
          body: GestureDetector(
            behavior: HitTestBehavior.opaque,
            onTap: () {
              _playAnimation();
            },
            child: Center(
              child: Container(
                width: 300.0,
                height: 300.0,
                decoration: BoxDecoration(
                  color: Colors.black.withOpacity(0.1),
                  border: Border.all(
                    color:  Colors.black.withOpacity(0.5),
                  ),
                ),
                child: StaggerAnimation(
                  controller: _controller.view
                ),
              ),
            ),
          ),
        );
      }
    }
    

    资源

    编写动画时,以下资源可能会有所帮助:

    Animations landing page

    列出Flutter动画的可用文档。 如果补间对您来说不熟悉,请查看动画教程

    Flutter API documentation

    所有Flutter库的参考文档。 特别是,请参阅动画库文档。

    Flutter Gallery

    演示应用程序展示了许多材料组件和其他Flutter功能。 Shrine demo实现了英雄动画。

    Material motion spec

    描述材料应用的动作。

    相关文章

      网友评论

          本文标题:(Flutter)交错动画【译】

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