Flutter: resumen de animación

1. Descripción de la API de animación:
la animación se completa con la cooperación de Animation, Curve, AnimationController y Tween.

1.La animación se usa para guardar el valor de transición y el estado de la animación:

addListener():监听每一帧的回调事件。
addStatusListener():监听动画状态改变事件,AnimationStatus.forward为开始、completed为结束、reverse为反向、dismissed为终止。

ejemplo:

Animation anim = CurvedAnimation(parent: animController, curve: Curves.linear);

2.La curva se usa para establecer el efecto de animación:

Constantes de efecto:

Curves.linear(匀速的)、decelerate(匀减速)、ease(开始加速,后面减速)、easeIn(开始慢,后面快)、easeOut(开始快,后面慢)、easeInOut(开始慢,然后加速,最后再减速)等

Curva personalizada:

class MyCurve extends Curve {
  @override
  double transform(double 原值) {
    return 新值; //自定义规则计算新值
  }
}

3.AnimationController se utiliza para controlar la animación:

AnimationController animController = AnimationController(
  duration: const Duration(milliseconds: 动画时长),
  lowerBound: 开始值,  //默认为0.0,默认范围[0.0,1.0]
  upperBound: 结束值,  //默认为1.0,默认范围[0.0,1.0]
  vsync: this,
);
...
animController.forward();   //开始执行动画
animController.stop();      //停止动画
animController.reverse();   //反向播放动画

4. Tween se usa para generar valores de animación de diferentes rangos o tipos de datos (rango predeterminado [0.0, 1.0]):

Tween t = Tween<double>(begin: 开始值, end: 结束值);   //数值过渡
Tween t = ColorTween(begin: 开始颜色, end: 结束颜色);  //颜色值过渡
...
Animation<double> anim1 = t.animate(animController);   //Tween传入AnimationController,生成Animation
Animation<double> anim2 = t.animate(anim);             //Tween包装原有Animation,生成新的Animation

5. Ticker detiene la animación cuando la página actual está en segundo plano, simplemente implemente una de las siguientes clases:

with SingleTickerProviderStateMixin    //适合1个AnimationController
with TickerProviderStateMixin          //适合多个AnimationController

6. Función lerp de interpolación lineal (la imagen es una línea recta):

//a 为起始颜色,b为终止颜色,t为当前动画的进度[0,1]
Color.lerp(开始颜色, 结束颜色, 动画进度值);   //进度值为默认[0-1]
Size.lerp(开始大小, 结束大小, 动画进度值);
Rect.lerp(开始大小, 结束大小, 动画进度值);
Offset.lerp(开始偏移值, 结束偏移值, 动画进度值);
Decoration.lerp(开始装饰, 结束装饰, 动画进度值);
...
Tween t = Tween<double>(begin: 开始值, end: 结束值);
t.lerp(动画进度值);
...

Segundo, implementación de animación:

1. Animation+AnimationController+Curve+Tween realiza la animación de interpolación (el efecto es similar a la animación de interpolación):

(1) Método AnimatedBuilder (recomendado, use AnimatedBuilder para envolver el Widget para animarlo, omita ..addListener):

class _PageState extends State<AnimationPage> with SingleTickerProviderStateMixin { //with TickerProviderStateMixin适合多个AnimationController
  late Animation<double> animation;  //用于保存动画的过渡值和状态
  late AnimationController animController;   //动画控制类
  @override
  initState() {
    super.initState();
    animController = AnimationController(duration: const Duration(milliseconds: 5000), vsync: this); //创建动画控制类
    animation = CurvedAnimation(parent: animController, curve: Curves.easeInOut);                    //(非必须,不添加时为匀速)添加另外动画效果
    animation = Tween(begin: 0.0, end: 300.0).animate(animation);                                    //Tween将值从0-300,包装带动画效果的Animation,生成新的Animation
    animation.addStatusListener((status) { //监听动画状态改变事件,AnimationStatus.forward为开始、completed为结束、reverse为反向、dismissed为终止
      //...
    });
  }
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ElevatedButton(child: Text("开始动画"),
            onPressed: () {
              animController.forward(); //开始执行动画
            }),
      AnimatedBuilder( //使用AnimatedBuilder包装要动画的Widget
          animation: animController,
          builder: (BuildContext ctx, child) {
            return Container(width: animation.value, height: animation.value, color: Colors.blue);  //通过animation.value值的改变产生动画效果
          })
      ]);
  }
  @override
  dispose() {
    animController.dispose(); //释放动画资源
    super.dispose();
  }
}

(2) Método AnimatedWidget (la clase personalizada hereda AnimatedWidget, envuelve el Widget para animarlo y omite ..addListener):

class ... { //同方式1
  ...  //同方式1
  @override
  initState() {
    ...  //同方式1
    animation = Tween(...).animate(animation);  //省略..addListener方法
  }
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ...,  //同方式1
        CustomImage(animation: animation)  //使用自定义AnimatedWidge
      ]);
  }
  ...  //同方式1
}
class CustomImage extends AnimatedWidget {
  const CustomImage({Key? key, required Animation<double> animation}) : super(key: key, listenable: animation);
  @override
  Widget build(BuildContext context) {
    final animation = listenable as Animation<double>;  //获取Animation
    return Image.asset("images/header.png", width: animation.value, height: animation.value);  //通过animation.value值的改变产生动画效果
  }
}

(3) Método 3 (menos recomendado, agregar manualmente ..addListener para ejecutar setState):

class ... { //同方式1
  ...  //同方式1
  @override
  initState() {
    ...  //同方式1
    animation = Tween(...).animate(animation) //同方式1
      ..addListener(() {    //需要添加..addListener方法监听每一帧的回调事件
        setState(() => {}); //更新UI状态
      });
  }
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ...,  //同方式1
        Image.asset("images/header.png", width: animation.value, height: animation.value)  //通过animation.value值的改变产生动画效果
      ]);
  }
  ...  //同方式1
}

(4) Clase de transición preestablecida del sistema:

FadeTransition(opacity: animation, child: Widget类());   //渐隐渐显过渡
ScaleTransition(scale: animation, child: Widget类());    //放大缩小过渡
SizeTransition(sizeFactor: animation, child: Widget类());//位移过渡

2. Realice la animación de salto de página:

El sistema viene con la clase de animación de salto de página:

MaterialPageRoute:与系统页面保持一致的页面跳转动画
CupertinoPageRoute:iOS风格的页面跳转动画

(1) PageRouteBuilder implementa animación de salto de página:

Navigator.push(context,
    PageRouteBuilder(  //PageRouteBuilder实现自定义页面跳转动画
      transitionDuration: Duration(milliseconds: 跳转过渡时长),
      pageBuilder: (BuildContext context, Animation<double> animation, Animation secondaryAnimation) {
        return FadeTransition(opacity: animation, child: 页面2()); //此处根据不同过渡类实现不同页面跳转效果
      }
    ));

(2) Personalice la clase PageRoute para realizar la animación de salto de página:

class MyPageRoute extends PageRoute {//自定义PageRoute类,修改过渡动画
  MyPageRoute({
    required this.builder,
    this.transitionDuration = const Duration(milliseconds: 1000),  //过渡时长
    this.maintainState = true,
    this.barrierLabel = "",
    this.barrierColor = Colors.blue, //动画切换时页面周边的颜色
  });
  @override
  Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) => builder(context);
  @override
  Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
    return ScaleTransition(scale: animation, child: builder(context));    //此处配置动画过渡类
  }
  final WidgetBuilder builder;
  @override
  final Duration transitionDuration;
  @override
  final bool maintainState;
  @override
  final String barrierLabel;
  @override
  final Color barrierColor;
}
...
Navigator.push(context, MyPageRoute(builder: (context) { //使用自定义PageRoute类实现页面跳转动画
  return Page2();
}));

3. Hero se da cuenta de la animación de vuelo:
se da cuenta del efecto visual: el Widget especificado en la primera página vuela a la posición especificada en la otra página

(1) Implementación de la página 1 (empaquetar el Widget para volar con Hero):

class HeroPage1 extends StatelessWidget {//页面1
  const HeroPage1({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: const Text("页面1标题")),
        body: Row(
          children: <Widget>[
            Hero( //将child的Widget执行飞行动画
                tag: "Hero-Tag", //Hero动画唯一标记,切换的两个页面Hero的tag要一致
                child: Image.asset( "images/header.png",)   //待飞行的Widget
            ),
            ElevatedButton(  //只是用来点击触发动画用
                child: Text("点击触发飞行动画"),
                onPressed: () {
                  Navigator.push(context, PageRouteBuilder( //页面跳转
                    pageBuilder: (BuildContext context, animation, secondaryAnimation) {
                      return FadeTransition(opacity: animation, child: HeroPage2());  //FadeTransition为渐隐渐入过渡动效,HeroPage2为第2个页面
                    },
                  ));
                })
          ],
        ));
  }
}

(2) Implementación de la página 2 (empaquetar el terminal de vuelo Widget con Hero):

class HeroPage2 extends StatelessWidget {//页面2
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: const Text("页面2标题")),
        body: Hero(
          tag: "Hero-Tag", //Hero动画唯一标记,切换的两个页面Hero的tag要一致
          child: Image.asset("images/photo.jpg") //飞行停止后的最终Widget
        ));
  }
}

4. Animación entrelazada (grupo de animación, múltiples animaciones al mismo tiempo):

Descripción:
varias animaciones
deben ser controladas por un AnimationController.
Se puede especificar un intervalo para cada animación.

Interval( //动画执行时长截取类
  0.2, 0.8, //对动画原时长截取,例:动画时长为5秒时,只在1秒-4秒之间执行动画,0-1秒与4-5秒不执行
  curve: Curves.easeInSine,
)

(1) Las animaciones múltiples se encapsulan en widgets, que están controlados por AnimationController pasado externamente:

class AnimGroupWidget extends StatelessWidget { //封装了多个动画的Widget
  AnimGroupWidget({Key? key, required this.animController}) : super(key: key);
  late final AnimationController animController;    //由外部传入1个AnimationController,控制所有动画
  late final Animation<double> anim1 = Tween<double>(begin: 0, end: 100).animate(animController);  //动画1,此处为数值渐变动画
  late final Animation<Color?> anim2 = ColorTween(begin: Colors.green, end: Colors.red).animate(animController);  //动画2,此处为颜色渐变动画
  late final Animation<double> anim3 = Tween<double>(begin: 0, end: 100).animate(CurvedAnimation( //动画3,此处使用了Interval
    parent: animController,
    curve: const Interval( //动画执行时长
      0.2, 0.8, //对动画原时长截取,例:动画时长为5秒时,只在1秒-4秒之间执行动画,0-1秒与4-5秒不执行
      curve: Curves.easeInSine,
    ),
  ));
  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(animation: animController,
      builder: (BuildContext ctx, child) {
        return Container(width: anim1.value, height: anim1.value, color: anim2.value); //Container根据动画1+动画2,改变背景色与宽高
      }
    );
  }
}

(2) Use el Widget del grupo de animación y controle la animación de inicio:

class _PageState extends State<Page1> with TickerProviderStateMixin {
  late AnimationController animController; //控制多个动画
  @override
  void initState() {
    super.initState();
    animController = AnimationController(duration: const Duration(milliseconds: 5000), vsync: this);
  }
  @override
  Widget build(BuildContext context) {
    return Column(children: [
        ElevatedButton(
          onPressed: () {
            animController.forward(); //开始动画(多个动画同时进行)
          },
          child: Text("点击开始多个动画"),
        ),
        AnimGroupWidget(animController: animController) //AnimGroupWidget封装了多个动画的Widget,传入统一的AnimationController
      ],
    );
  }
}

5. AnimatedSwitcher implementa la animación de cambio de Widget:

late List<T> layoutList;
...
AnimatedSwitcher( //AnimatedSwitcher也是Widget
  reverseDuration: Duration(milliseconds: 2000),  //旧child隐藏的动画时长
  duration: Duration(milliseconds: 2000),         //新child显示的动画时长
  switchOutCurve: Curves.easeInOut,               //旧child隐藏的动画效果
  switchInCurve: Curves.easeInOut,                //新child显示的动画效果
  transitionBuilder: (Widget child, Animation<double> animation) { //动画构造器
    return FadeTransition(child: child, opacity: animation);  //过渡类
  },
  child: layoutList[position],  //需要动画的布局,同个布局名要设置不同的key才有动画效果
)

6. Realice la animación de transición cuando cambie la propiedad Widget:

(1) AnimatedPadding, la animación de transición se realiza cuando cambia el valor del relleno:

double padding = 0;  //旧padding值
...
AnimatedPadding(
    duration: Duration(milliseconds: 2000),
    padding: EdgeInsets.all(padding),   //此值改变时执行过渡动画
    child: Text("AnimatedPadding测试")
)
...
setState(() {
  padding = 10;   //设为新padding值时执行过渡动画
});

(2) AnimatedPositioned (utilizado junto con Stack), la animación de transición se realiza cuando cambia la posición o el tamaño:

double position = 0;  //旧位置
...
Stack(
  children: <Widget>[
    AnimatedPositioned(
        duration: Duration(milliseconds: 2000),
        left: position,  //此值改变时执行过渡动画
        top: position,   //此值改变时执行过渡动画
        child: Text("AnimatedPositioned测试")
    )
  ]
)
...
setState(() {
  position = 40;  //设为新位置时执行过渡动画
});

(3) AnimatedAlign, ejecuta la animación de transición cuando cambia la alineación:

Alignment align = Alignment.topLeft;  //旧对齐方式
...
AnimatedAlign(
  duration: Duration(milliseconds: 2000),
  alignment: align,     //此值改变时执行过渡动画
  child: Text("AnimatedAlign测试"),
)
...
setState(() {
  align = Alignment.bottomRight; //设为新对齐方式时触发动画
});

(4) AnimatedOpacity, la animación de transición se realiza cuando cambia la opacidad de la transparencia:

double opacity = 0.5;  //旧透明度
...
AnimatedOpacity(
  duration: Duration(milliseconds: 2000),
  opacity: scale,   //此值改变时执行过渡动画
  child: Text("AnimatedOpacity测试")
)
...
setState(() {
  opacity = 0.5; //设为新透明度时触发动画
});

(5) AnimatedContainer, la animación de transición se realiza cuando cambia el valor de la propiedad:

double size = 50;  //旧宽高
...
AnimatedContainer(
  duration: Duration(milliseconds: 2000),
  width: size,        //此值改变时执行过渡动画
  height: size,       //此值改变时执行过渡动画
  child: Text("AnimatedContainer测试")
)
...
setState(() {
  size = 100; //设为新宽高时触发动画
});

(6) AnimatedDefaultTextStyle, realiza una animación de transición cuando cambia el estilo de fuente:

TextStyle style = const TextStyle(fontSize: 14, color: Colors.red);  //旧样式
...
AnimatedDefaultTextStyle(
    duration: Duration(milliseconds: 2000),
    style: style,        //此值改变时执行过渡动画
    child: Text("AnimatedDefaultTextStyle测试")),
...
setState(() {
  style = const TextStyle(fontSize: 16, color: Colors.yellow); //设为新样式时触发动画
});


 

Supongo que te gusta

Origin blog.csdn.net/a526001650a/article/details/127654284
Recomendado
Clasificación