AnimatedBuilder


如果你需要的不只是單向的動畫,想要控制更多動畫細節,Flutter 內建了一些 AnimatedWidget 的子類別,這些可以在 API 文件中查詢,像是 ScaleTransitionRotationTransitionPositionedTransition 等。

類似地,內建的隱式動畫 Widget 沒辦法滿足時,你可以進一步使用 TweenAnimationBuilder,必要時將實作細節封裝為 ImplicitlyAnimatedWidget 的子類;若內建的顯式動畫 Widget 沒辦法滿足時,也可以進一步使用 AnimatedBuilder,必要時將實作細節封裝為 AnimatedWidget 的子類。

來看個使用 AnimatedBuilder 的例子,在〈TweenAnimationBuilder〉中的染色範例,只會單向地播放,若想要重複不停、往復式地播放,可以如下撰寫:

import 'package:flutter/material.dart';

void main() => runApp(
  MaterialApp(
    home: Caterpillar(),
  )
);

class Caterpillar extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _CaterpillarState();
}

class _CaterpillarState extends State<Caterpillar> with SingleTickerProviderStateMixin {
  var start = false;

  AnimationController _animation;

  @override
  void initState() {
    super.initState();
    _animation = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..stop();
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('openhome.cc'),
      ),
      body: Center(
        // 使用 AnimatedBuilder
        child: AnimatedBuilder(
          animation: _animation,
          builder: (_, __) {
            return Image(
              image: NetworkImage('https://openhome.cc/Gossip/images/caterpillar.jpg'),
              // 將 AnimationController 的 value 轉為特性
              color: Color.lerp(Colors.white, Colors.red, _animation.value),
              colorBlendMode: BlendMode.colorBurn,
            );
          }
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => setState(() {
          start = !start;
          if(start) {
            _animation.repeat(reverse: true);
          }
          else {
            _animation.stop();
          }
        }),
        tooltip: start ? 'Stop' : 'Start',
        child: Icon(start ? Icons.stop : Icons.play_arrow),
      ),
    );
  }
}

大部份需要的實作,與〈TweenAnimationBuilder〉中談到的是相同的,AnimatedBuilderbuilder,第一個參數是 BuildContext,第二個參數是 child,也就是必要時,也可以指定 AnimatedBuilderchild,這會傳入 builder 指定的函式中,重複使用以增進效能。

最主要的不同是,你要將 AnimationControllervalue 轉為目標特性,這邊使用了 Color.lerp,指定的參數分別是 beginend 以及 t,你可能會想:「嗯?該怎麼套用動畫曲線呢?」,實際上,這等於套用 Curves.linear,之後再套用 ColorTween,這需要接觸更多動畫細節,留待之後的文件再來討論。

來看一下執行效果:

AnimatedBuilder