用Flutter實現一個仿Twitter的點贊效果

  這次依然是補作業,之前在寫仿“探探”左滑/右滑的效果的時候,設計稿底部的喜歡Icon其實是有類似於Twitter點贊那種的動效的,但是因爲時間原因我偷懶沒寫。
  慣例先上效果圖:

 

  GitHub地址:https://github.com/yumi0629/FlutterUI/tree/master/lib/likebutton

  整體算法是參照了GitHub上star最多的jd-alexander大佬寫的LikeButton,我進行了調整,並最終用Flutter實現。
  一點小缺陷:現在的實現方式,icon大小沒法自適應,需要初始化佈局的時候手動傳入一個size。

設計思路

  我們將動畫放慢,很明顯整體動畫由三部分組成:中間Icon的放大、底部圓環的交替和外部煙花散開的效果:

 

 

整體佈局

  因爲是層疊佈局,我們依舊是使用Stack來實現,底部圓環的交替和外部煙花散開的效果是使用的CustomPaint來繪製,而中間的小圖標則是使用的普通Widget實現:

Stack(
      alignment: Alignment.center,
      children: <Widget>[
        CustomPaint(
          size: Size(widget.width, widget.width),
          painter: DotPainter(),
        ),
        CustomPaint(
          isComplex: true,
          size: Size(widget.width * 0.35, widget.width * 0.35),
          painter: CirclePainter(),
        Container(
          width: widget.width,
          height: widget.width,
          alignment: Alignment.center,
          child: Transform.scale(
            scale: isLiked ? scale.value : 1.0,
            child: GestureDetector(
              child: Icon(),
              onTap: _onTap,
            ),
          ),
        ),
      ],
    );

  Paint的繪製在這裏就不多說了,因爲基本都是數學問題。整體效果的實現主要是要學會用一個Controller來控制多個動畫。

動畫控制 Staggered Animation

  這一期主要是想跟大家講講如何用一個Controller來控制多個動畫同時進行,也就是Flutter中的Staggered Animation(交錯動畫)。
  我們可以定義很多個Animation,將他們和同一個controller綁定:

Animation<double> outerCircle = new Tween<double>(
      begin: 0.1,
      end: 1.0,
    ).animate(
      new CurvedAnimation(
        parent: _controller,
        curve: new Interval(
          0.0,
          0.3,
          curve: Curves.ease,
        ),
      ),
    );
    Animation<double> innerCircle = new Tween<double>(
      begin: 0.2,
      end: 1.0,
    ).animate(
      new CurvedAnimation(
        parent: _controller,
        curve: new Interval(
          0.2,
          0.5,
          curve: Curves.ease,
        ),
      ),
    );Animation<double> 

  上面的例子中,outerCircleinnerCircle共享同一個_controller,而各自的播放順序通過Interval來控制:outerCircle的動畫時間爲整體進度的0.0~0.3,innerCircle的動畫時間爲整體進度的0.2~0.5。對於單個動畫的進度,我們可以通過outerCircle.valueinnerCircle.value來獲取,單個動畫的進度範圍依然是0.0~1.0,所以繪製每一組動畫時,不需要去手動轉換。

繪製中的一些坑

  這次碰到的主要問題是paintblendMode屬性有坑,因爲底部兩個圓環在繪製時的思路是:大圓環繪製到一半時,開始繪製小圓環將其遮蓋住,但是小圓環的顏色我們沒法設定,因爲我們不知道畫布是什麼顏色的,因此沒法用相同的顏色去遮蓋住大圓環。這個問題可以通過設置paintblendMode屬性爲BlendMode.clear解決,看名字就很好理解,就是清楚之前的繪製區域,但是這個BlendMode.clear有bug。
  如果你直接向下面這樣寫,那麼你會發現,clear掉的部分會變成黑色:

 

  解決方法就是在繪製前保存一下當前layer:

canvas.saveLayer(Offset.zero & size, Paint());
canvas.drawCircle(Offset(center, center), 20.0, circlePaint);
canvas.drawCircle(Offset(center, center), 10.0, maskPaint);
canvas.restore();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章