Code前端首页关于Code前端联系我们

Flutter动画开发:基于Tween界面和物理

terry 2年前 (2023-09-23) 阅读数 66 #移动小程序

UI合理的动画设计可以让用户感觉更加流畅直观,改善用户交互体验,提升用户体验。

Flutter中的动画分为两类:基于Tween的和基于物理的;

中间动画是两者之间的简称,在中间动画中定义起点,定义时间变化和速度的终点、时间点和曲线,然后系统计算如何从起点开始指向终点。

物理动画是模拟的运动,其行为就像在现实世界中一样,例如投掷物体。就像数学一样,它落地的位置取决于物体的重量、投掷速度以及物体距地面的高度。抛物线运动轨道。

简介

在Flutter中实现动画效果需要几个基本函数:Animation(动画对象)、AnimationController(动画控制器)、Tweens(插值器)、Curves(动画曲线);

1。动画

Flutter 中的动画本身与渲染用户界面无关。动画是一个抽象类,具有当前值和状态(已完成或已停止)。 Flutter 中的动画系统基于对象 Animation 。最常用的一种是动画类。它可以通过其 value 属性检索当前动画的值。除了生成双值之外,

Animation 还可以生成颜色,例如:颜色--Animation 或大小--Animation

动画对象可以具有监听器和状态监听器,可以使用 addListener()addStatusListener() 添加。每当动画值发生变化时就会调用侦听器。我们通常在监听器中调用setState()来触发UI重建;当动画开始、结束、向前或向后移动时,会调用 StatusListener。

2。 AnimationController

AnimationController 是一个特殊的 Animation 对象,它为屏幕刷新的每一帧创建一个新值。默认情况下,AnimationController 将随时间线性生成从 0.0 到 1.0 的数字。 AnimationController 派生自 Animation,因此它可以在需要 Animation 对象的任何地方使用。不仅如此,AnimationController还有其他方法来控制动画,比如forward()方法来启动动画。

AnimationController({
    double value,
    this.duration,
    this.reverseDuration,
    this.debugLabel,
    this.lowerBound = 0.0,
    this.upperBound = 1.0,
    this.animationBehavior = AnimationBehavior.normal,
    @required TickerProvider vsync,
  })
复制代码

创建AnimationController必须下载vsync。传递 vsunc 可防止动画 UI 不在当前屏幕上时绘制,从而防止不必要的资源消耗。通过将 SingleTickerProviderStateMixin 混合到类定义中,您可以将状态对象用作 vsync 值。

除了vsync还可以传递正向动画运行时间duration和反向动画运行时间reverseDuration等吗? 重做动画

4reverse()反向播放动画。必须是播放前进动画的状态。 开始动画

注意:动画结束后处理控制器(调用dispose()方法)以避免内存泄漏

@override
void dispose() {
  animationController.dispose();
  super.dispose();
}
复制代码

3、Tween

默认情况下, AnimationController 对象的范围从 0、0 到 1.0。如果需要不同的范围或不同的数据类型,可以使用 Tween 来配置动画以创建不同范围或数据类型的值。例如,您可以创建从 0 到 100 的数字:

final Tween doubleTween = new Tween<double>(begin: 0.0, end: 100.0);
复制代码

Tween 是一个无状态对象,它继承自 Animatable,而不是继承自 Animation 。补间需要两个值:开始和结束。 Tween 的唯一职责是定义输入到输出范围的映射。

Animatable 与动画类似。它不必输出双精度值,它也可以是一种颜色,例如从白色到黑色:

final Tween colorTween = new ColorTween(begin: Colors.withe, end: Colors.black);
复制代码

Tween 可以通过 animate() 方法传递控制器对象来创建动画对象。如下图

AnimationController _animationController = AnimationController(animationBehavior:AnimationBehavior.normal,vsync: this);
Tween<double> _tween = Tween<double>(begin: 0.0, end: 100.0)..animate(_animationController);
复制代码

4,CurvedAnimation

Curves用于调整动画过程中随时间变化的速率。默认情况下,动画在单个线性模型中变化。 Flutter 内部还提供了一组 Curves 对象来执行适当的变化率:linea ------ 线性、deceleration ------ 减速等。

当然,你也可以自定义一个继承曲线的类来指定动画的变化率,如:

class ShakeCurve extends Curve {
  @override
  double transform(double t) {
    return math.sin(t * math.PI * 2);
  }
}
复制代码

5。添加跟踪

目前,动画仅检测其自身值的变化,不会导致小部件移动。这里我们需要跟踪动画值,然后使用 setstatus 更新小部件属性以使小部件移动。

添加数值监控:

Animation animation = CurvedAnimation(parent: _animationController, curve: Curves.linear);
    animation.addListener((){
      setState(() {
        
      });
    });
复制代码

此外,我们还可以监控动画状态的变化。当动画结束时,我们反转动画。当翻转动画也结束时,我们重新启动动画以继续动画。这个循环继续下去。

状态更改侦听器:

animation.addStatusListener((status){
      print(status);
    });
复制代码

6、AnimatedWidget

AnimatedWidget 类允许您在调用 setState() 时将小部件代码与动画代码分开。 AnimatedWidget不需要维护一个State对象来存储动画。

以下代码改编自AnimatedLogo官方文档

import 'package:flutter/animation.dart';
import 'package:flutter/material.dart';

class AnimatedLogo extends AnimatedWidget {
  AnimatedLogo({Key key, Animation<double> animation})
      : super(key: key, listenable: animation);

  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;
    return new Center(
      child: new Container(
        margin: new EdgeInsets.symmetric(vertical: 10.0),
        height: animation.value,
        width: animation.value,
        child: new FlutterLogo(),
      ),
    );
  }
}

class LogoApp extends StatefulWidget {
  _LogoAppState createState() => new _LogoAppState();
}

class _LogoAppState extends State<LogoApp> with SingleTickerProviderStateMixin {
  AnimationController controller;
  Animation<double> animation;

  initState() {
    super.initState();
    controller = new AnimationController(
        duration: const Duration(milliseconds: 2000), vsync: this);
    animation = new Tween(begin: 0.0, end: 300.0).animate(controller);
    controller.forward();
  }

  Widget build(BuildContext context) {
    return new AnimatedLogo(animation: animation);
  }

  dispose() {
    controller.dispose();
    super.dispose();
  }
}
复制代码

AnimatedWidget为什么不需要维护一个State对象来存储动画呢?

查看AnimatedWidget的源码可以看到,AnimatedWidget继承于StatefulWidget类中AnimatedWidget 创建一个有状态的小部件。_AnimatedState,然后看类_AnimatedState的源码部分:_AnimatedState中的

abstract class AnimatedWidget extends StatefulWidget{
  
   @override
  _AnimatedState createState() => _AnimatedState();
  
}
复制代码

类方法initState

添加监控_AnimatedState._handleChange 并在方法 didUpdateWidgetdispose_handleChang e 中删除其中只有一行代码,即 setState .方法:

_AnimatedState源码

class _AnimatedState extends State<AnimatedWidget> {
  @override
  void initState() {
    super.initState();
    // 添加监听
    widget.listenable.addListener(_handleChange);
  }

  @override
  void didUpdateWidget(AnimatedWidget oldWidget) {
    super.didUpdateWidget(oldWidget);
    // 移除
    if (widget.listenable != oldWidget.listenable) {
      oldWidget.listenable.removeListener(_handleChange);
      widget.listenable.addListener(_handleChange);
    }
  }

  @override
  void dispose() {
    // 移除
    widget.listenable.removeListener(_handleChange);
    super.dispose();
  }

  void _handleChange() {
    // 更新状态
    setState(() {
      // The listenable's state is our build state, and it changed already.
    });
  }

  @override
  Widget build(BuildContext context) => widget.build(context);
}
复制代码

7.并行动画

所谓并行动画就是几个动画一起执行。在Flutter中,您可以在同一个动画控制器上使用多个Tween,然后每个Tween处理动画中的不同效果。 ,它允许多个动画同时运行。

final AnimationController controller =
    new AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
final Animation<double> sizeAnimation =
    new Tween(begin: 0.0, end: 300.0).animate(controller);
final Animation<double> opacityAnimation =
    new Tween(begin: 0.1, end: 1.0).animate(controller);
复制代码

你可以通过sizeAnimation.value获取尺寸,通过opacityAnimation.value获取不透明度,但AnimatedWidget构造函数只接受一个动画对象。为了解决这个问题,您可以创建自己的 Tween 对象并显式计算值。

build方法.evaluate()调用父动画对象上的Tween函数来计算所需的size和 不透明度

价值。? ingleTickerProviderStateMixin 用于 TickerProviderStateMixin 。

完结

作者:小风藏月
链接:https://juejin.im/post/5d8b2d36e51d4577f4608ae2
来源:掘金
版权归作者所有。商业转载请联系作者获得许可。非商业转载请注明来源。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门