flutter动画 (一) 从loading的转圈动画说起 - Ticker

原创文章
声明:作者声明此文章为原创,未经作者同意,请勿转载,若转载,务必注明本站出处,本平台保留追究侵权法律责任的权利。
全栈老韩
全栈工程师,擅长iOS App开发、前端(vue、react、nuxt、小程序&Taro)开发、Flutter、React Native、后端(midwayjs、golang、express、koa)开发、docker容器、seo优化等。

引言

flutter中的动画一个重要且必不可少的机制就是Ticker,所以要理解flutter的动画,必须先要对Ticker有所理解。

对于Ticker这个概念,可以将其理解为时钟或者刷新信号。意味着,在UI IT开发领域共识中,每秒60帧刷新频率下,Ticker会发出信号去执行动画,并且在这个频率之下,Ticker在每一帧都提供了回调给到开发者去进行处理。

常见的SingleTickerProviderStateMixin

以上是对Ticker的简单介绍,下面介绍一个轻量且高效的tiker provider SingleTickerProviderStateMixin,说到provider,你应该就知道SingleTickerProviderStateMixin是一个提供了Ticker的对象,而从其命名中就可以看出,这是一个混入mixin对象,而且通常用于处理单独的某一种动画时常用的ticker提供对象【使用多动画则考虑使用TickerProviderStateMixin】,咱们看看它的声明:

ticker_provider.dart 复制代码
/// Provides a single [Ticker] that is configured to only tick while the current
/// tree is enabled, as defined by [TickerMode].
///
/// To create the [AnimationController] in a [State] that only uses a single
/// [AnimationController], mix in this class, then pass `vsync: this`
/// to the animation controller constructor.
///
/// This mixin only supports vending a single ticker. If you might have multiple
/// [AnimationController] objects over the lifetime of the [State], use a full
/// [TickerProviderStateMixin] instead.
@optionalTypeArgs
mixin SingleTickerProviderStateMixin<T extends StatefulWidget> on State<T> implements TickerProvider {
  Ticker? _ticker;
...
}

所以它可以被状态组件StatefulWidgetState进行混入处理。而且在SingleTickerProviderStateMixin中已经包含Ticker对象,在dispose中也会处理removeListener,

ticker_provider.dart 复制代码
...
@override
  void dispose() {
    assert(() {
      if (_ticker == null || !_ticker!.isActive) {
        return true;
      }
      throw FlutterError.fromParts(<DiagnosticsNode>[
        ErrorSummary('$this was disposed with an active Ticker.'),
        ErrorDescription(
          '$runtimeType created a Ticker via its SingleTickerProviderStateMixin, but at the time '
          'dispose() was called on the mixin, that Ticker was still active. The Ticker must '
          'be disposed before calling super.dispose().',
        ),
        ErrorHint(
          'Tickers used by AnimationControllers '
          'should be disposed by calling dispose() on the AnimationController itself. '
          'Otherwise, the ticker will leak.',
        ),
        _ticker!.describeForError('The offending ticker was'),
      ]);
    }());
    _tickerModeNotifier?.removeListener(_updateTicker);
    _tickerModeNotifier = null;
    super.dispose();
  }
...

所以在使用SingleTickerProviderStateMixin时,你不必担心Ticker的回收内存泄漏问题。

loading动画案例

这里我们写一个简单的转圈动画,代码如下:

loading.dart 复制代码
import 'package:flutter/cupertino.dart';

class LoadingWidget extends StatefulWidget {

  late final Widget? loadingWidget;

  LoadingWidget({ super.key, this.loadingWidget });

  @override
  _LoadingWidgetWidgetState createState() => _LoadingWidgetWidgetState();
}

class _LoadingWidgetWidgetState extends State<LoadingWidget>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 1),
      vsync: this,
    )..repeat(); // 持续动画
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: (context, child) {
        return Transform.rotate(
          angle: _controller.value * 2.0 * 3.141592653589793,
          child: child,
        );
      },
      child: widget.loadingWidget != null ? widget.loadingWidget : Image.asset(
        'assets/images/loading.png', // 转圈图片
        width: 24,
        height: 24,
      ),
    );
  }
}

示例图片:
loading flutter

上面一段代码通过使用AnimationController动画控制器,在参数vsync传入了当前的state作为ticker provider,动画时长duration为1秒,在AnimatedBuilder动画生成器中builder下传入了转圈动画Transform.rotate,角度是当前动画进度的值,乘以一圈的弧度 2 pi,那么1秒钟一圈的动画,持续不断的repeat重复执行,就组成了loading转圈的效果。

以上就是对loading动画的一个简单解释说明,在这个基础上,如果想进行其他动画,比如:translate、scale、flip等就都可以用这个思路实现。

希望对大家有帮助,也请大家多多关注“新卫网络科技”微信公众号。

暂无评论,快来发表第一条评论吧