flutter动画 (一) 从loading的转圈动画说起 - Ticker
引言
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;
...
}
所以它可以被状态组件StatefulWidget的State进行混入处理。而且在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,
),
);
}
}
示例图片:

上面一段代码通过使用AnimationController动画控制器,在参数vsync传入了当前的state作为ticker provider,动画时长duration为1秒,在AnimatedBuilder动画生成器中builder下传入了转圈动画Transform.rotate,角度是当前动画进度的值,乘以一圈的弧度 2 pi,那么1秒钟一圈的动画,持续不断的repeat重复执行,就组成了loading转圈的效果。
以上就是对loading动画的一个简单解释说明,在这个基础上,如果想进行其他动画,比如:translate、scale、flip等就都可以用这个思路实现。
希望对大家有帮助,也请大家多多关注“新卫网络科技”微信公众号。
暂无评论,快来发表第一条评论吧