flutter系列之:使用AnimationController來控制動畫效果

2023-05-17 12:00:12

簡介

之前我們提到了flutter提供了比較簡單好用的AnimatedContainer和SlideTransition來進行一些簡單的動畫效果,但是要完全實現自定義的複雜的動畫效果,還是要使用AnimationController。

今天我們來嘗試使用AnimationController來實現一個拖拽圖片,然後返回原點的動畫。

構建一個要動畫的widget

在本文的例子中,我們希望能夠讓一個圖片可以實現拖拽然後自動返回原來位置的效果。

為了實現這個功能,我們首先構建一個放在介面中間的圖片。

      child: Align(
        alignment: Alignment.center,
        child: Card(
          child: Image(image: AssetImage('images/head.jpg'))
        ),
      )

這裡使用了Align元件,將一個圖片物件放在介面中間。

接下來我們希望這個widget可以拖拽,那麼把這個child放到一個GestureDetector中,這樣就可以相應拖拽對應的響應。

 Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
    return GestureDetector(

      onPanUpdate: (details) {
        setState(() {
          _animateAlign += Alignment(
            details.delta.dx / (size.width / 2),
            details.delta.dy / (size.height / 2),
          );
        });
      },

      child: Align(
        alignment: _animateAlign,
        child: Card(
          child: widget.child,
        ),
      ),
    );
  }

為了能實現拖動的效果,我們需要在GestureDetector的onPanUpdate方法中對Align的位置進行修改,所以我們需要呼叫setState方法。

在setState方法中,我們根據手勢的位置來調整Alignment的位置,所以這裡需要用到MediaQuery來獲取螢幕的大小。

但是現在實現的效果是影象隨手勢移動而移動,我們還需要實現在手放開之後,影象自動回覆到原來位置的動畫效果。

讓影象動起來

因為這次需要變動的是Alignment,所以我們先定義一個包含Alignment的Animation屬性:

  late Animation<Alignment> _animation;

接下來我們需要定義一個AnimationController,用來控制動畫資訊,並且指定我們需要的動畫起點和終點:

  late AnimationController _controller;

      _animation = _controller.drive(
      AlignmentTween(
        begin: _animateAlign,
        end: Alignment.center,
      ),
    );

我們動畫的起點位置就是當前image所在的Alignment,終點就在Alignment.center。

Alignment有一個專門表示位置資訊的類叫做AlignmentTween,如上程式碼所示。

有了起點和終點, 我們還需要指定從起點移動到終點的方式,這裡模擬使用彈簧效果,所以使用SpringSimulation。

SpringSimulation需要提供對spring的描述,起點距離,結束距離和初始速度。

    const spring = SpringDescription(
      mass: 30,
      stiffness: 1,
      damping: 1,
    );

    final simulation = SpringSimulation(spring, 0, 1, -1);

我們使用上面建立的simulation,來實現動畫:

    _controller.animateWith(simulation);

最後我們需要在手勢結束的時候來執行這個動畫即可:

      onPanEnd: (details) {
        _runAnimation();
      },

最後,執行效果如下所示:

總結

AnimationController是一個很強大的元件,但是使用起來也不是那麼的複雜, 我們只需要定義好起點和終點,然後指定動畫效果即可。

本文的例子:https://github.com/ddean2009/learn-flutter.git