精选文章 Flutter Animation动画开发之——AnimationStatusListener动画状态监听

Flutter Animation动画开发之——AnimationStatusListener动画状态监听

作者:野猿新一 时间: 2019-11-07 10:14:05
野猿新一 2019-11-07 10:14:05

源码分析

在之前的文章中我们介绍过Animation的addListener可以用来监听动画每一帧的变化

而如果要监听动画的状态变化,就要用到Animation的void addStatusListener(AnimationStatusListener listener)方法

addStatusListener方法是定义在AnimationLocalStatusListenersMixin中的,Animation抽象类的实现都有withAnimationLocalStatusListenersMixin,比如AnimationController

class AnimationController extends Animation
  with AnimationEagerListenerMixin, AnimationLocalListenersMixin, AnimationLocalStatusListenersMixin {

}

我们再看下withAnimationLocalStatusListenersMixin的源码

  • didRegisterListener():在添加动画状态监听前调用,该方法需融合withAnimationLocalStatusListenersMixin的类来实现

  • addStatusListener(AnimationStatusListener listener):添加动画状态监听

  • removeStatusListener(AnimationStatusListener listener):移除动画状态监听

  • didUnregisterListener():在移除动画状态监听后调用,该方法需融合withAnimationLocalStatusListenersMixin的类来实现

  • notifyStatusListeners(AnimationStatus status):动画状态变化的通知,通知所有注册的AnimationStatusListener

/// A mixin that implements the addStatusListener/removeStatusListener protocol
/// and notifies all the registered listeners when notifyStatusListeners is
/// called.
///
/// This mixin requires that the mixing class provide methods [didRegisterListener]
/// and [didUnregisterListener]. Implementations of these methods can be obtained
/// by mixing in another mixin from this library, such as [AnimationLazyListenerMixin].
mixin AnimationLocalStatusListenersMixin {
  final ObserverList _statusListeners = ObserverList();

  /// Called immediately before a status listener is added via [addStatusListener].
  ///
  /// At the time this method is called the registered listener is not yet
  /// notified by [notifyStatusListeners].
  void didRegisterListener();

  /// Called immediately after a status listener is removed via [removeStatusListener].
  ///
  /// At the time this method is called the removed listener is no longer
  /// notified by [notifyStatusListeners].
  void didUnregisterListener();

  /// Calls listener every time the status of the animation changes.
  ///
  /// Listeners can be removed with [removeStatusListener].
  void addStatusListener(AnimationStatusListener listener) {
    didRegisterListener();
    _statusListeners.add(listener);
  }

  /// Stops calling the listener every time the status of the animation changes.
  ///
  /// Listeners can be added with [addStatusListener].
  void removeStatusListener(AnimationStatusListener listener) {
    final bool removed = _statusListeners.remove(listener);
    if (removed) {
      didUnregisterListener();
    }
  }

  /// Calls all the status listeners.
  ///
  /// If listeners are added or removed during this function, the modifications
  /// will not change which listeners are called during this iteration.
  void notifyStatusListeners(AnimationStatus status) {
    final List localListeners = List.from(_statusListeners);
    for (AnimationStatusListener listener in localListeners) {
      try {
        if (_statusListeners.contains(listener))
          listener(status);
      } catch (exception, stack) {
        FlutterError.reportError(FlutterErrorDetails(
          exception: exception,
          stack: stack,
          library: 'animation library',
          context: ErrorDescription('while notifying status listeners for $runtimeType'),
          informationCollector: () sync* {
            yield DiagnosticsProperty(
              'The $runtimeType notifying status listeners was',
              this,
              style: DiagnosticsTreeStyle.errorProperty,
            );
          },
        ));
      }
    }
  }
}

接下来我们在看下AnimationStatus的源码,AnimationStatus是一个枚举类,共定义了如下几种动画状态

  •   dismissed:回到动画起点处
  •   forward:从起点往终点方向执行
  •   reverse:从终点往起点反方向执行
  •   completed:到达动画终点处
/// The status of an animation
enum AnimationStatus {
  /// The animation is stopped at the beginning
  dismissed,

  /// The animation is running from beginning to end
  forward,

  /// The animation is running backwards, from end to beginning
  reverse,

  /// The animation is stopped at the end
  completed,
}

示例代码

看完源码分析,接下我我们写一个示例跑一下

一下示例中演示了一个绿色的方块,宽高从100变化到200,由于监听了动画的状态,当动画执行到终点时会反向执行,当反向执行到起点时又会再正向执行,如此循环往复就可以实现无限循环动画(当然,AnimationController.repeat()也可实现动画循环播放)

绿色方块汇总还有两个Text

当动画到达起点时第一个Text显示“起点”,当动画到达终点时第一个Text显示“终点”

当动画往前正向执行时第二个Text显示“正向”,当动画往后反向执行时第二个Text显示“反向”

大家可以直接拷贝如下整段代码运行看下效果

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: AnimationRoute(),
    );
  }
}

class AnimationRoute extends StatefulWidget {
  @override
  AnimationRouteState createState() => AnimationRouteState();
}

class AnimationRouteState extends State with SingleTickerProviderStateMixin {

  AnimationController controller;
  String position = '';
  String direction = '';

  initState() {
    super.initState();
    // Controller设置动画时长
    // vsync设置一个TickerProvider,当前State 混合了SingleTickerProviderStateMixin就是一个TickerProvider
    controller = AnimationController(
        lowerBound: 100,
        upperBound: 200,
        duration: Duration(seconds: 5),
        vsync: this //
    )..addStatusListener((status){
        if (status == AnimationStatus.dismissed) {
          controller.forward();
          setState(() {
            position = '起点';
          });
        } else if (status == AnimationStatus.forward) {
          setState(() {
            direction = '正向';
          });
        } else if (status == AnimationStatus.reverse) {
          setState(() {
            direction = '反向';
          });
        } else if (status == AnimationStatus.completed) {
          controller.reverse();
          setState(() {
            position = '终点';
          });
        }
      });
    //启动动画(正向执行)
    controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
        animation: controller,
        builder: (BuildContext ctx, Widget child) {
          return Center(
            child: Container(
              color: Colors.green,
              alignment: Alignment.center,
              width: controller.value,
              height: controller.value,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(position,
                    style: TextStyle(
                      color: Colors.black,
                      fontSize: 18.0,
                    ),
                  ),
                  Text(direction,
                    style: TextStyle(
                      color: Colors.black,
                      fontSize: 18.0,
                    ),
                  )
                ],
              ),
            ),
          );
        }
    );
  }

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

 

 

 

勿删,copyright占位
分享文章到微博
分享文章到朋友圈

上一篇:PHP中array_merge函数与array+array的区别

下一篇:Linux (Ubuntu)使用命令行安装JDK

CSDN

CSDN

中国开发者社区CSDN (Chinese Software Developer Network) 创立于1999年,致力为中国开发者提供知识传播、在线学习、职业发展等全生命周期服务。