Flutter實(shí)戰(zhàn) 交織動(dòng)畫(huà)

2021-03-08 18:01 更新

有些時(shí)候我們可能會(huì)需要一些復(fù)雜的動(dòng)畫(huà),這些動(dòng)畫(huà)可能由一個(gè)動(dòng)畫(huà)序列或重疊的動(dòng)畫(huà)組成,比如:有一個(gè)柱狀圖,需要在高度增長(zhǎng)的同時(shí)改變顏色,等到增長(zhǎng)到最大高度后,我們需要在X軸上平移一段距離??梢园l(fā)現(xiàn)上述場(chǎng)景在不同階段包含了多種動(dòng)畫(huà),要實(shí)現(xiàn)這種效果,使用交織動(dòng)畫(huà)(Stagger Animation)會(huì)非常簡(jiǎn)單。交織動(dòng)畫(huà)需要注意以下幾點(diǎn):

  1. 要?jiǎng)?chuàng)建交織動(dòng)畫(huà),需要使用多個(gè)動(dòng)畫(huà)對(duì)象(Animation)。
  2. 一個(gè)AnimationController控制所有的動(dòng)畫(huà)對(duì)象。
  3. 給每一個(gè)動(dòng)畫(huà)對(duì)象指定時(shí)間間隔(Interval)

所有動(dòng)畫(huà)都由同一個(gè) AnimationController (opens new window) 驅(qū)動(dòng),無(wú)論動(dòng)畫(huà)需要持續(xù)多長(zhǎng)時(shí)間,控制器的值必須在0.0到1.0之間,而每個(gè)動(dòng)畫(huà)的間隔(Interval)也必須介于0.0和1.0之間。對(duì)于在間隔中設(shè)置動(dòng)畫(huà)的每個(gè)屬性,需要分別創(chuàng)建一個(gè) Tween (opens new window)用于指定該屬性的開(kāi)始值和結(jié)束值。也就是說(shuō)0.0到1.0代表整個(gè)動(dòng)畫(huà)過(guò)程,我們可以給不同動(dòng)畫(huà)指定不同的起始點(diǎn)和終止點(diǎn)來(lái)決定它們的開(kāi)始時(shí)間和終止時(shí)間。

#示例

下面我們看一個(gè)例子,實(shí)現(xiàn)一個(gè)柱狀圖增長(zhǎng)的動(dòng)畫(huà):

  1. 開(kāi)始時(shí)高度從0增長(zhǎng)到300像素,同時(shí)顏色由綠色漸變?yōu)榧t色;這個(gè)過(guò)程占據(jù)整個(gè)動(dòng)畫(huà)時(shí)間的60%。
  2. 高度增長(zhǎng)到300后,開(kāi)始沿X軸向右平移100像素;這個(gè)過(guò)程占用整個(gè)動(dòng)畫(huà)時(shí)間的40%。

我們將執(zhí)行動(dòng)畫(huà)的 Widget 分離出來(lái):

class StaggerAnimation extends StatelessWidget {
  StaggerAnimation({ Key key, this.controller }): super(key: key){
    //高度動(dòng)畫(huà)
    height = Tween<double>(
      begin:.0 ,
      end: 300.0,
    ).animate(
      CurvedAnimation(
        parent: controller,
        curve: Interval(
          0.0, 0.6, //間隔,前60%的動(dòng)畫(huà)時(shí)間
          curve: Curves.ease,
        ),
      ),
    );


    color = ColorTween(
      begin:Colors.green ,
      end:Colors.red,
    ).animate(
      CurvedAnimation(
        parent: controller,
        curve: Interval(
          0.0, 0.6,//間隔,前60%的動(dòng)畫(huà)時(shí)間
          curve: Curves.ease,
        ),
      ),
    );


    padding = Tween<EdgeInsets>(
      begin:EdgeInsets.only(left: .0),
      end:EdgeInsets.only(left: 100.0),
    ).animate(
      CurvedAnimation(
        parent: controller,
        curve: Interval(
          0.6, 1.0, //間隔,后40%的動(dòng)畫(huà)時(shí)間
          curve: Curves.ease,
        ),
      ),
    );
  }




  final Animation<double> controller;
  Animation<double> height;
  Animation<EdgeInsets> padding;
  Animation<Color> color;


  Widget _buildAnimation(BuildContext context, Widget child) {
    return Container(
      alignment: Alignment.bottomCenter,
      padding:padding.value ,
      child: Container(
        color: color.value,
        width: 50.0,
        height: height.value,
      ),
    );
  }


  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      builder: _buildAnimation,
      animation: controller,
    );
  }
}

StaggerAnimation中定義了三個(gè)動(dòng)畫(huà),分別是對(duì)Containerheight、color、padding屬性設(shè)置的動(dòng)畫(huà),然后通過(guò)Interval來(lái)為每個(gè)動(dòng)畫(huà)指定在整個(gè)動(dòng)畫(huà)過(guò)程中的起始點(diǎn)和終點(diǎn)。下面我們來(lái)實(shí)現(xiàn)啟動(dòng)動(dòng)畫(huà)的路由:

class StaggerRoute extends StatefulWidget {
  @override
  _StaggerRouteState createState() => _StaggerRouteState();
}


class _StaggerRouteState extends State<StaggerRoute> with TickerProviderStateMixin {
  AnimationController _controller;


  @override
  void initState() {
    super.initState();


    _controller = AnimationController(
        duration: const Duration(milliseconds: 2000),
        vsync: this
    );
  }




  Future<Null> _playAnimation() async {
    try {
      //先正向執(zhí)行動(dòng)畫(huà)
      await _controller.forward().orCancel;
      //再反向執(zhí)行動(dòng)畫(huà)
      await _controller.reverse().orCancel;
    } on TickerCanceled {
      // the animation got canceled, probably because we were disposed
    }
  }


  @override
  Widget build(BuildContext context) {
    return  GestureDetector(
      behavior: HitTestBehavior.opaque,
      onTap: () {
        _playAnimation();
      },
      child: Center(
        child: Container(
          width: 300.0,
          height: 300.0,
          decoration: BoxDecoration(
            color: Colors.black.withOpacity(0.1),
            border: Border.all(
              color:  Colors.black.withOpacity(0.5),
            ),
          ),
          //調(diào)用我們定義的交織動(dòng)畫(huà)Widget
          child: StaggerAnimation(
              controller: _controller
          ),
        ),
      ),
    );
  }
}

執(zhí)行效果如圖,點(diǎn)擊圖9-3灰色矩形,就可以看到整個(gè)動(dòng)畫(huà)效果,圖9-4是動(dòng)畫(huà)執(zhí)行過(guò)程中的一幀。

圖9-3圖9-4

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)