Flutter實戰動畫番外篇-翻頁效果實現

前言

前段時間學習Flutter動畫時接觸了Transform類,查找官方文檔時無心間看到了時鐘翻頁動畫以爲也挺好玩的,因此就本身動手使用動畫和Transform來實現翻頁特效。html

思路

開始前本身也思考過若是實現翻頁動畫,但實際操做時卻發現思路不太正確最後只好做罷。最後仍是參考了已有翻頁實現方式瞭解實現原理,其實方法很簡單經過Transform對數字上部分進行矩陣變化操做實現頁面翻轉效果。下面經過圖解方式更好解釋實現過程。git

圖解

下圖所展現內容是從橫切面看到的效果。正常狀況下是從示例圖左邊到右邊的查看視角👉。github

  • STEP1
    首先可使用ClipRect組件將數字分割成上下兩部分。用A和D來顯示翻頁的下一個數字。C和B則顯示當前準備翻轉的數字。開始時咱們看到就是C和B組成當前數字。
  • STEP2
    而後數字上部分C使用Transform進行變形旋轉達到向上翻轉動畫效果:setEntry進行變形處理,rotateX向X軸作旋轉操做,翻轉角度爲90度。
  • STEP3
    當C旋轉90度過程當中底部A數字上部分就會慢慢呈現出來。接着C旋轉到90度以後,開始是垂直不可見D也進行90度向X軸旋轉操做。這個過程當中上個數字的下部分B就慢慢被遮蓋。
  • STEP4
    最後D旋轉了90度後整個動畫週期就結束了,當前數字顯示的就是下一個值。最後一步同時將A、B、C、D分別更改成下次須要顯示的數值並將C、D重置回原來的位置進行下一輪動畫。

代碼部分

  • 數字分割部分
ClipRect(
      child: Align(
        alignment: _alignment,
        heightFactor: 0.5,
        child: Container(
          alignment: Alignment.center,
          width: 100,
          decoration: BoxDecoration(
            color: Colors.black,
            borderRadius: BorderRadius.all(Radius.circular(4.0)),
          ),
          child: Text(
            "$_value",
            style: TextStyle(
              fontSize: 80,
              color: Colors.white,
              fontWeight: FontWeight.w700,
            ),
          ),
        ),
      ),
    )
複製代碼
  • 數字總體
Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Stack(
          children: <Widget>[
            //下一個數字的上部分
            ClipRectText(_stateNum + 1, Alignment.topCenter),
            //當前數字的上部分,當_isReversePhase爲true時和平面呈90度角至關於隱藏
            Transform(
                transform: Matrix4.identity()
                  ..setEntry(3, 2, 0.006)
                  ..rotateX(_isReversePhase ? pi / 2 : _animation.value),
                alignment: Alignment.bottomCenter,
                child: ClipRectText(_stateNum, Alignment.topCenter)),
          ],
        ),
        Padding(
          padding: EdgeInsets.only(top: 2.0),
        ),
        Stack(
          children: <Widget>[
            //當前數字的下部分
            ClipRectText(_stateNum, Alignment.bottomCenter),
            //下個數字的下部分,當_isReversePhase爲true時才執行翻轉動畫不然一直和平面呈90度
            Transform(
                transform: Matrix4.identity()
                  ..setEntry(3, 2, 0.006)
                  ..rotateX(_isReversePhase ? -_animation.value : pi / 2),
                alignment: Alignment.topCenter,
                child: ClipRectText(_stateNum + 1, Alignment.bottomCenter)),
          ],
        )
      ],
    )
複製代碼
  • 動畫實現
_controller = new AnimationController(
        duration: Duration(milliseconds: 450), vsync: this)
      ..addStatusListener((status) {
        //動畫正向執行,正向執行結束後進行反向執行
        if (status == AnimationStatus.completed) {
          _controller.reverse();
          _isReversePhase = true;
        }
        //動畫反向執行,反向執行結束後一次動畫翻轉週期結束。當前數字更新到最新的
        if (status == AnimationStatus.dismissed) {
          _isReversePhase = false;
          _stateNum += 1;
        }
      })
      ..addListener(() {
        setState(() {});
      });
    //動畫數值使用0度角到90度角
    _animation = Tween(begin: _zeroAngle, end: pi / 2).animate(_controller);
  
複製代碼
  • 動畫觸發條件
@override
  void didUpdateWidget(FlipNumText oldWidget) {
    //當組件的數字num發生改變時執行動畫控制器
    if (this.widget.num != oldWidget.num) {
      _controller.forward();
      _stateNum = oldWidget.num;
    }
    super.didUpdateWidget(oldWidget);
  }
複製代碼

🚀完整代碼看這裏🚀算法

最後

翻頁動畫效果實現中不少運用到了數學算法。如Pi角度、Transform的2D、3D變換、Matrix矩陣使用等都離不開數學計算。目前對於Matrix還只停留在使用上,後續須要深刻理解其原理才能更好的運用。同時也但願有小夥伴一塊兒交流共同進步😸😊。api

參考

相關文章
相關標籤/搜索