_AnimatedState 介绍



class _AnimatedState extends State<AnimatedWidget> {
  void initState() {

  void didUpdateWidget(AnimatedWidget oldWidget) {
    if (widget.listenable != oldWidget.listenable) {

  void dispose() {

  void _handleChange() {
    setState(() {
      // The listenable's state is our build state, and it changed already.

  Widget build(BuildContext context) => widget.build(context);

Ticker 和 TickerProvider 介绍


/// Calls its callback once per animation frame.
/// When created, a ticker is initially disabled. Call [start] to
/// enable the ticker.
/// A [Ticker] can be silenced by setting [muted] to true. While silenced, time
/// still elapses, and [start] and [stop] can still be called, but no callbacks
/// are called.
/// By convention, the [start] and [stop] methods are used by the ticker's
/// consumer, and the [muted] property is controlled by the [TickerProvider]
/// that created the ticker.
/// Tickers are driven by the [SchedulerBinding]. See
/// [SchedulerBinding.scheduleFrameCallback].
class Ticker {
  /// Creates a ticker that will call the provided callback once per frame while
  /// running.
  /// An optional label can be provided for debugging purposes. That label
  /// will appear in the [toString] output in debug builds.
  Ticker(this._onTick, { this.debugLabel }) {
    assert(() {
      _debugCreationStack = StackTrace.current;
      return true;


  /// * `vsync` is the [TickerProvider] for the current context. It can be
  ///   changed by calling [resync]. It is required and must not be null. See
  ///   [TickerProvider] for advice on obtaining a ticker provider.
    double value,
    this.lowerBound = 0.0,
    this.upperBound = 1.0,
    this.animationBehavior = AnimationBehavior.normal,
    @required TickerProvider vsync,
  }) : assert(lowerBound != null),
       assert(upperBound != null),
       assert(upperBound >= lowerBound),
       assert(vsync != null),
       _direction = _AnimationDirection.forward {
    _ticker = vsync.createTicker(_tick);
    _internalSetValue(value ?? lowerBound);

而我们通常在使用SingleTickerProviderStateMixin,这种mixin解决了管理ticker的麻烦。 只需在Widget的State上添加该mixin,现在的State就秘密地变成了TickerProvider,意思就是Flutter framework会向我们的State对象寻求一个ticker对象,重要的是AnimationController可以向State寻求一个ticker。这样当我们调用AnimationController的dispose方法时,也就是页面退出(动画不应该再继续显示)的时候,可以不再继续调用Ticker的回调函数,来避免内存泄漏和提高性能。

class _MyWidgetState extends State<MyWidget> 
    with SingleTickerProviderStateMixin<MyWidget> {
  Widget build(BuildContext context) {
    return Container();


/// 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.
mixin SingleTickerProviderStateMixin<T extends StatefulWidget> on State<T> implements TickerProvider {
  Ticker _ticker;

  Ticker createTicker(TickerCallback onTick) {
    assert(() {
      if (_ticker == null)
        return true;
      throw FlutterError.fromParts(<DiagnosticsNode>[
        ErrorSummary('$runtimeType is a SingleTickerProviderStateMixin but multiple tickers were created.'),
        ErrorDescription('A SingleTickerProviderStateMixin can only be used as a TickerProvider once.'),
          'If a State is used for multiple AnimationController objects, or if it is passed to other '
          'objects and those objects might use it more than one time in total, then instead of '
          'mixing in a SingleTickerProviderStateMixin, use a regular TickerProviderStateMixin.'
    _ticker = Ticker(onTick, debugLabel: kDebugMode ? 'created by $this' : null);
    // We assume that this is called from initState, build, or some sort of
    // event handler, and that thus TickerMode.of(context) would return true. We
    // can't actually check that here because if we're in initState then we're
    // not allowed to do inheritance checks yet.
    return _ticker;





class MyPragmaticWidget extends StatelessWidget {
  Widget build(BuildContext context) {
    return TweenAnimationBuilder(
      tween: IntTween(begin: 0, end: 299792458),
      duration: const Duration(seconds: 1),
      builder: (BuildContext context, int i, Widget child) {
        return Text('$i m/s');

参考:Animation deep dive