91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Flutter如何利用Canvas模擬實現微信紅包領取效果

發布時間:2022-03-21 19:50:13 來源:億速云 閱讀:483 作者:iii 欄目:開發技術

這篇文章主要介紹了Flutter如何利用Canvas模擬實現微信紅包領取效果的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Flutter如何利用Canvas模擬實現微信紅包領取效果文章都會有所收獲,下面我們一起來看看吧。

效果

最終實現的整體效果如下:

Flutter如何利用Canvas模擬實現微信紅包領取效果

看完效果以后,接下來就帶領大家來看看是怎樣一步一步實現最終效果的,在正式動手寫代碼之前,先對整個效果做一個簡單的拆分,將其分為五個部分:

  • 點擊彈出紅包

  • 紅包整體布局

  • 金幣點擊旋轉

  • 紅包開啟動畫

  • 結果頁面彈出

拆分后如下圖所示:

Flutter如何利用Canvas模擬實現微信紅包領取效果

接下來就一步一步來實現。

紅包彈出

紅包彈出主要分為兩部分:從小到大縮放動畫、半透明遮罩。很自然的想到了使用 Dialog 來實現,最終也確實使用 Dialog 實現了對應的效果,但是在最后展示結果頁的時候出現問題了,因為紅包開啟與結果展示是同時進行的,結果頁在紅包下面,使用 Dialog 的話會存在結果頁在 Dialog 上面遮住紅包的效果,最后使用了 Overlay 在頂層添加一個 Widget 來實現。

創建一個 RedPacket 的 Widget:

class RedPacket extends StatelessWidget {
  const RedPacket({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
        child: Container(
          width: 0.8.sw,
          height: 1.2.sw,
          color: Colors.redAccent,
        )
    );
  }
}

內容很簡單,就是一個居中的寬高分別為 0.8.sw1.2.sw 的 Container,顏色為紅色。這里 sw 是代表屏幕寬度,即紅包寬度為屏幕寬度的 0.8 倍,高度為屏幕寬度的 1.2 倍。

關于 Flutter 屏幕適配,請參閱:Flutter應用框架搭建之屏幕適配詳解

然后點擊按鈕時通過 Overlay 展示出來, 創建一個 showRedPacket 的方法:

void showRedPacket(BuildContext context){
  OverlayEntry entry = OverlayEntry(builder: (context) => RedPacket());
  Overlay.of(context)?.insert(entry);
}

效果如下:

Flutter如何利用Canvas模擬實現微信紅包領取效果

紅包是彈出來了,但因為沒有縮放動畫,很突兀。為了實現縮放動畫,在 Container 上包裹 ScaleTransition 用于縮放動畫,同時將 RedPacket 改為 StatefulWidget ,因為使用動畫需要用到 AnimationController 傳入 SingleTickerProviderStateMixin ,實現如下:

class RedPacket extends StatefulWidget {

  const RedPacket({Key? key}) : super(key: key);

  @override
  State<RedPacket> createState() => _RedPacketState();
}

class _RedPacketState extends State<RedPacket> with SingleTickerProviderStateMixin {
  late AnimationController scaleController = AnimationController(vsync: this)
    ..duration = const Duration(milliseconds: 500)
    ..forward();

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Color(0x88000000), /// 半透明遮罩
      child: Center(
          child: ScaleTransition(
            scale: Tween<double>(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: scaleController, curve: Curves.fastOutSlowIn)),
            child: Container(
              width: 0.8.sw,
              height: 1.2.sw,
              color: Colors.redAccent,
            ),
          )
      ),
    );
  }
}

ScaleTransition 設置動畫從 0.0 到 1.0 即從無到原本大小,動畫時間為 500 毫秒;同時在外層再包裹一層 Container 并為其添加半透明顏色實現半透明遮罩,最終實現效果:

Flutter如何利用Canvas模擬實現微信紅包領取效果

這樣就實現了第一部分的功能。

紅包布局

標題說了是使用 Canvas 來實現,所以紅包布局主要是使用 Canvas 來實現,將前面紅包的 Container 換成 CustomPaint, 然后創建 RedPacketPainter 繼承自 CustomPainter :

ScaleTransition(
  scale: Tween<double>(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: scaleController, curve: Curves.fastOutSlowIn)),
  child: CustomPaint(
    size: Size(1.sw, 1.sh),
    painter: RedPacketPainter(),
  ),
)

考慮到后續動畫,這里將畫布的大小設置為全屏。紅包布局的核心代碼就在 RedPacketPainter 里,首先繪制紅包的背景,背景分為上下兩部分,上部分又由一個矩形和一個圓弧組成,下半部分同樣是由一個矩形和一個圓弧組成,上半部分的圓弧是凸出來的,而下半部分的是凹進去的,示意圖如下:

Flutter如何利用Canvas模擬實現微信紅包領取效果

初始化:

/// 畫筆 
late final Paint _paint = Paint()..isAntiAlias = true;
/// 路徑
final Path path = Path();

/// 紅包的高度:1.2倍的屏幕寬度
late double height = 1.2.sw;

/// 上半部分貝塞爾曲線的結束點
late double topBezierEnd = (1.sh - height)/2 + height/8*7;
/// 上半部分貝塞爾曲線的起點
late double topBezierStart= topBezierEnd - 0.2.sw;
/// 下半部分貝塞爾曲線的起點
late double bottomBezierStart = topBezierEnd - 0.4.sw;

/// 金幣中心點,后續通過path計算
Offset goldCenter = Offset.zero;

/// 橫向的中心點
final double centerWidth = 0.5.sw;

/// 紅包在整個界面的left
late double left = 0.1.sw;
/// 紅包在整個界面的right
late double right = 0.9.sw;
/// 紅包在整個界面的top
late double top = (1.sh - height)/2;
/// 紅包在整個界面的bottom
late double bottom = (1.sh - height)/2 + height;

上半部分

代碼實現如下:

void drawTop(ui.Canvas canvas) {  
  path.reset();
  path.addRRect(RRect.fromLTRBAndCorners(left, top, right, topBezierStart, topLeft: const Radius.circular(5), topRight: const Radius.circular(5)));
  var bezierPath = getTopBezierPath();
  path.addPath(bezierPath, Offset.zero);
  path.close();

  canvas.drawShadow(path, Colors.redAccent, 2, true);
  canvas.drawPath(path, _paint);
}

這里使用 Path 來進行繪制,首先向路徑中添加一個圓角矩形,也就是示意圖中的第①部分,然后通過 getTopBezierPath 獲取一個貝塞爾曲線的 bezierPath 并將其添加到 path 路徑中,getTopBezierPath 源碼如下:

Path getTopBezierPath() {
  Path bezierPath = Path();
  bezierPath.moveTo(left, topBezierStart);
  bezierPath.quadraticBezierTo(centerWidth, topBezierEnd, right , topBezierStart);

  var pms = bezierPath.computeMetrics();
  var pm = pms.first;
  goldCenter = pm.getTangentForOffset(pm.length / 2)?.position ?? Offset.zero;
  return bezierPath;
}

getTopBezierPath 源碼分為兩部分,第一部分是創建貝塞爾曲線的 path ,使用的是最開始初始化的數據創建,實現示意圖中的第②部分內容;然后根據創建好的貝塞爾曲線的 path 計算出路徑中中間點的坐標,作為金幣中心點坐標。示意圖如下:

Flutter如何利用Canvas模擬實現微信紅包領取效果

圖中紅點就是貝塞爾曲線的點,中間實線就是貝塞爾曲線,也就是上面代碼中創建的貝塞爾曲線路徑,實線中間的點就是金幣位置的中心點。

貝塞爾曲線繪制完成后調用 drawShadow 繪制陰影,作用是突出上下兩部分連接處的效果,最后通過 path 繪制出整個上半部分的效果,如下:

Flutter如何利用Canvas模擬實現微信紅包領取效果

下半部分

代碼實現如下:

void drawBottom(ui.Canvas canvas) {
  path.reset();
  path.moveTo(left, bottomBezierStart );
  path.quadraticBezierTo(centerWidth, topBezierEnd, right , bottomBezierStart);
  
  path.lineTo(right, topBezierEnd);
  path.lineTo(left, topBezierEnd);
  
  path.addRRect(RRect.fromLTRBAndCorners(left, topBezierEnd, right, bottom, bottomLeft: const Radius.circular(5), bottomRight: const Radius.circular(5)));
  path.close();
  
  canvas.drawShadow(path, Colors.redAccent, 2, true);
  
  canvas.drawPath(path, _paint);
}

下半部分實現同樣分為兩部分,首先繪制出貝塞爾曲線,即示意圖第③部分,然后再添加一個圓角矩形,即示意圖第④部分;然后繪制下半部分的陰影和圖形,單獨展示下半部分效果如下:

Flutter如何利用Canvas模擬實現微信紅包領取效果

將上下兩部分結合起來,就實現了紅包背景的效果,如下:

Flutter如何利用Canvas模擬實現微信紅包領取效果

金幣繪制

背景繪制完成后接下來進行金幣的繪制,前面已計算出金幣的中心點坐標,靜態金幣的繪制就相對來說比較簡單了,就是一個圓形,代碼如下:

void drawGold(ui.Canvas canvas){
  Path path = Path();

  canvas.save();
  canvas.translate(0.5.sw, goldCenter.dy);

  _paint.style = PaintingStyle.fill;
  path.addOval(Rect.fromLTRB(-40.w , -40.w, 40.w , 40.w));

  _paint.color = const Color(0xFFFCE5BF);
  canvas.drawPath(path, _paint);

  canvas.restore();
}

這里將畫布移動到到金幣的中心點,然后向 Path 中添加添加一個半徑為 40.w 的圓,最后將 path 繪制出來即可。效果如下:

Flutter如何利用Canvas模擬實現微信紅包領取效果

金幣文字繪制

金幣繪制出來后,還需在金幣上繪制一個繁體的 "開" 字,代碼如下:

void drawOpenText(ui.Canvas canvas) {
  if(controller.showOpenText){
    TextPainter textPainter = TextPainter(
      text: TextSpan(
        text: "開",
        style: TextStyle(fontSize: 34.sp, color: Colors.black87, height: 1.0, fontWeight: FontWeight.w400)
      ),
      textDirection: TextDirection.ltr,
      maxLines: 1,
      textWidthBasis: TextWidthBasis.longestLine,
      textHeightBehavior: const TextHeightBehavior(applyHeightToFirstAscent: false, applyHeightToLastDescent: false)
    )..layout();

    canvas.save();
    canvas.translate(0.5.sw, goldCenter.dy);
    textPainter.paint(canvas, Offset(- textPainter.width / 2, -textPainter.height/2));
    canvas.restore();
  }
}

使用 TextPainter 進行文字的繪制,同樣是將畫布移動到金幣的中心,然后繪制文字,效果如下:

Flutter如何利用Canvas模擬實現微信紅包領取效果

頭像和文字

經過上面的繪制,效果已經出來了,但是還差紅包封面上的用戶頭像相關文字,使用 Canvas 同樣能實現,但這里并沒有使用 Canvas 來實現,而是使用 CoustomPaint 的 child 來實現:

CustomPaint(
  size: Size(1.sw, 1.sh),
  painter: RedPacketPainter(controller: controller),
  child: buildChild(),
)

Container buildChild() {
  return Container(
    padding: EdgeInsets.only(top: 0.3.sh),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ClipRRect(
              borderRadius: BorderRadius.circular(3.w),
              child: Image.network("https://p26-passport.byteacctimg.com/img/user-avatar/32f1f514b874554f69fe265644ca84e4~300x300.image", width: 24.w,)),
            SizedBox(width: 5.w,),
            Text("loongwind發出的紅包", style: TextStyle(fontSize: 16.sp, color: Color(
              0xFFF8E7CB), fontWeight: FontWeight.w500),)
          ],
        ),
        SizedBox(height: 15.w,),
        Text("恭喜發財", style: TextStyle(fontSize: 18.sp, color: Color(
          0xFFF8E7CB)),)
      ],
    ),
  );
}

CoustomPaint 的 child 允許傳入一個 Widget,Widget 的實現就是要顯示的頭像和文字,代碼如上,最終效果如下:

Flutter如何利用Canvas模擬實現微信紅包領取效果

至此紅包的整個布局的實現就完成了。

金幣旋轉

前面完成了紅包的靜態顯示,接下來就看看怎么讓紅包動起來,首先看看怎么讓金幣旋轉起來。

說到旋轉首先想到的就是以金幣的中心旋轉,可以通過旋轉畫布的旋轉或者 path 的 transform 旋轉來實現,但是經過實驗使用這種方式能讓金幣旋轉起來,但是做到旋轉的立體效果卻很復雜。所以最終采用的是使用兩個圓在 x 軸上進行一定的偏移,然后壓縮圓的寬度來模擬實現旋轉效果,示意圖如下:

Flutter如何利用Canvas模擬實現微信紅包領取效果

如圖所示,繪制兩個相同的圓,開始時將兩個圓重疊在一起,然后同時壓縮圓的寬度并將下層的圓向左偏移一定單位,就形成了旋轉的立體效果。

代碼:

void drawGold(ui.Canvas canvas){
  Path path = Path();

  canvas.save();
  canvas.translate(0.5.sw, goldCenter.dy);

  _paint.style = PaintingStyle.fill;
  path.addOval(Rect.fromLTRB(-40.w , -40.w, 40.w , 40.w));

  _paint.color = const Color(0xFFE5CDA8);
  canvas.drawPath(path, _paint);

  _paint.color = const Color(0xFFFCE5BF);
  canvas.drawPath(path, _paint);

  canvas.restore();
}

修改上面繪制金幣的代碼,設置不同的顏色再繪制一個圓,這樣就在同一個位置繪制了兩個不同顏色的圓。那么怎么讓它動起來呢?可以使用動畫,通過動畫執行寬度的縮放,是寬度系數從 1 縮放到 0 再從 0 回到 1。因為 CustomPainter 是繼承自 Listenable ,而動畫也是 Listenable 所以直接將動畫與 CustomPainter 結合起來使用更方便。

為了方便統一控制紅包的動畫,創建一個 RedPacketController,并在里面創建一個控制金幣旋轉的動畫及控制器:

class RedPacketController{

  final SingleTickerProviderStateMixin tickerProvider;
  late AnimationController angleController;
  late Animation<double> angleCtrl;
  
  RedPacketController({required this.tickerProvider}){
    initAnimation();
  }
  
  void initAnimation() {
    angleController = AnimationController(
        duration: const Duration(seconds: 3),
        vsync: tickerProvider
    )..repeat(reverse: true);
    angleCtrl = angleController.drive(Tween(begin: 1.0, end: 0.0));
  }

  void dispose(){
    angleController.dispose();
    timer?.cancel();
  }
}

為了看到旋轉的效果,將動畫執行時間設置為 3 秒,并且讓其重復執行,重復執行時設置 reverse 為 true,即反向執行,然后改造 _RedPacketState 混入 SingleTickerProviderStateMixin 并創建 RedPacketController :

class _RedPacketState extends State<RedPacket> with SingleTickerProviderStateMixin{

  late RedPacketController controller = RedPacketController(tickerProvider: this);
  
  Widget buildRedPacket() {
    return GestureDetector(
      onTapUp: controller.clickGold,
      child: CustomPaint(
        size: Size(1.sw, 1.sh),
        painter: RedPacketPainter(controller: controller),
        child: buildChild(),
      ),
    );
  }
  /// ...
}

class RedPacketPainter extends CustomPainter{

  RedPacketController controller;

  RedPacketPainter({required this.controller}) : super(repaint:controller.angleController);
  
  /// ...
}

RedPacketPainter 的構造方法調用了 super 并傳入了 repaint 參數,即創建的動畫控制器。

這樣就能在繪制金幣的時候使用動畫的值了:

void drawGold(ui.Canvas canvas){
  Path path = Path();

  double angle = controller.angleCtrl.value;

  canvas.save();
  canvas.translate(0.5.sw, goldCenter.dy);

  _paint.style = PaintingStyle.fill;
  path.addOval(Rect.fromLTRB(-40.w * angle , -40.w, 40.w * angle, 40.w));

  _paint.color = const Color(0xFFE5CDA8);
  canvas.drawPath(path, _paint);

  _paint.color = const Color(0xFFFCE5BF);
  canvas.drawPath(path, _paint);

  canvas.restore();
}

通過 controller.angleCtrl.value 獲取當前動畫的值,然后在圓的 left 和 right 參數上乘以這個值,看一下效果:

Flutter如何利用Canvas模擬實現微信紅包領取效果

效果已經有了,但是發現在旋轉到最小的時候中間是空的,這不符合我們的預期,那怎么辦呢?將兩個圓的邊一一連接起來是不是中間就不空了,如圖所示:

Flutter如何利用Canvas模擬實現微信紅包領取效果

代碼實現:

void drawGoldCenterRect(ui.Path path, ui.Path path3, ui.Canvas canvas) {

  var pms1 = path.computeMetrics();
  var pms2 = path3.computeMetrics();

  var pathMetric1 = pms1.first;
  var pathMetric2 = pms2.first;
  var length = pathMetric1.length;
  Path centerPath = Path();
  for(int i = 0; i <length; i++){
    var position1 = pathMetric1.getTangentForOffset(i.toDouble())?.position;
    var position2 = pathMetric2.getTangentForOffset(i.toDouble())?.position;
    if(position1 == null || position2 == null){
      continue;
    }
    centerPath.moveTo(position1.dx, position1.dy);
    centerPath.lineTo(position2.dx, position2.dy);
  }

  Paint centerPaint = Paint()..color = const Color(0xFFE5CDA8)
    ..style = PaintingStyle.stroke..strokeWidth=1;
  canvas.drawPath(centerPath, centerPaint);
}

使用 Path.computeMetrics 計算兩個 path 的路徑點,循環路徑每一個點,將兩個 path 的每一個點連接起來然后繪制出來,再來看一下效果:

Flutter如何利用Canvas模擬實現微信紅包領取效果

效果好多了,但是仔細觀察發現還是有一個問題,金幣看著不是旋轉的而是左右搖擺的,這是因為實現的立體的效果一直在一邊導致的,需要根據旋轉的時機將立體效果的方向切換,從 1 到 0 時在右邊,從 0 到 1 時在左邊,通過動畫的狀態進行判斷,修改代碼如下:

var frontOffset = 0.0;
var backOffset = 0.0;
if(controller.angleCtrl.status == AnimationStatus.reverse){
  frontOffset = 4.w;
  backOffset = -4.w;
}else if(controller.angleCtrl.status == AnimationStatus.forward){
  frontOffset = -4.w;
  backOffset = 4.w;
}

var path3 = path.shift(Offset(backOffset * (1 - angle),  0));
path = path.shift(Offset(frontOffset * (1 - angle), 0));

再來看一下效果:

Flutter如何利用Canvas模擬實現微信紅包領取效果

這樣旋轉效果就很完美了,金幣中間還缺一個空心的矩形,實現很簡單,在圓的 path 路徑中疊加一個矩形即可:

path.addRect(Rect.fromLTRB(-10.w * angle , -10.w, 10.w * angle , 10.w));
path.fillType = PathFillType.evenOdd;

設置fillTypeevenOdd ,這樣就形成了中心空心的效果,并且由于上面連接兩個圓的路徑點,這個空心也自帶了立體效果,如圖:

Flutter如何利用Canvas模擬實現微信紅包領取效果

最后為金幣添加點擊事件,點擊時開啟旋轉,并隱藏金幣上的文字。點擊事件可以直接給 CustomPaint 包裹一個 GestureDetector ,點擊時判斷點擊坐標是否在金幣的繪制范圍內,可以使用 Path.contains 進行判斷,所以需要保存金幣的 path 用于點擊判斷,這里將其保存到 controller 里:

controller.goldPath = path.shift(Offset(0.5.sw, goldCenter.dy));

然后在 RedPacketController 里定義對應的變量和方法:

class RedPacketController{
  Path? goldPath;
  bool showOpenText = true;
  
  bool checkClickGold(Offset point){
    return  goldPath?.contains(point) == true;
  }
  
  void clickGold(TapUpDetails details) {
    if(checkClickGold(details.globalPosition)){
      angleController.repeat(reverse: true);
      tickerProvider.setState(() {
        showOpenText = false;
      });
    }
  }
 
  /// ...
}

goldPath 用于保存金幣的 path,showOpenText 用于是否顯示金幣上的文字,點擊時判斷事件觸發點是否在金幣范圍內,在金幣范圍內則觸發動畫啟動,并設置金幣上的文字不顯示。

為 CustomPaint 添加點擊事件:

Widget buildRedPacket() {
  return GestureDetector(
    onTapUp: controller.clickGold,
    child: CustomPaint(
      size: Size(1.sw, 1.sh),
      painter: RedPacketPainter(controller: controller),
      child: buildChild(),
    ),
  );
}

看一下效果 :

Flutter如何利用Canvas模擬實現微信紅包領取效果

紅包開啟

紅包開啟其實就是將紅包上下兩部分分別進行向上和向下的平移,再加上背景顏色的漸變實現,示意圖如下:

Flutter如何利用Canvas模擬實現微信紅包領取效果

加上之前金幣的動畫,存在多個動畫控制器,所以需要將 _RedPacketState 修改為混入 TickerProviderStateMixin:

class _RedPacketState extends State<RedPacket> with TickerProviderStateMixin{
  /// ...
}

然后在 RedPacketController 添加平移動畫控制器,并添加平移和顏色漸變動畫,平移系數從 0 到 1, 顏色漸變從不透明到完全透明。并將平移動畫與之前的金幣動畫合并為 repaint

class RedPacketController{

  final TickerProviderStateMixin tickerProvider;

  late AnimationController angleController;
  late AnimationController translateController;
  late Animation<double> translateCtrl;
  late Animation<Color?> colorCtrl;
  
  
  void initAnimation() {

    /// ...
    
    
    translateController = AnimationController(
        duration: const Duration(milliseconds: 800),
        vsync: tickerProvider
    );
    translateCtrl = translateController.drive(Tween(begin: 0.0, end: 1.0));
    colorCtrl = translateController.drive(ColorTween(
        begin: Colors.redAccent,
        end: const Color(0x00FF5252))
    );

    repaint = Listenable.merge([angleController, translateController]);
  }
}

再在 RedPacketPainter 的 super 里傳入 repaint:

RedPacketPainter({required this.controller}) : super(repaint:controller.repaint);

改造繪制紅包上半部分代碼:

void drawTop(ui.Canvas canvas) {
  canvas.save();
  canvas.translate(0, topBezierEnd  * ( - controller.translateCtrl.value));

  /// ...

  canvas.restore();
}

添加畫布平移操作,平移的 Y 值為上半部分高度乘以動畫值,即從 0 向上移動上半部分高度。

下半部分添加同樣的處理,平移方向向下:

void drawBottom(ui.Canvas canvas) {
  canvas.save();
  canvas.translate(0, topBezierStart * (controller.translateCtrl.value));

	/// ...

  canvas.restore();
}

效果如下:

Flutter如何利用Canvas模擬實現微信紅包領取效果

背景的平移效果實現了,但是上面的頭像和文字沒動,接下來給頭像和文字的 Widget 添加 AnimatedBuilder 使用相同的動畫讓其跟著移動:

Widget buildChild() {
    return AnimatedBuilder(
      animation: controller.translateController,
      builder: (context, child) => Container(
        padding: EdgeInsets.only(top: 0.3.sh * (1 - controller.translateCtrl.value)),
        child: Column(...),
      ),
    );
  }

通過動態修改 paddingTop 的值,讓頭像與文字也向上平移。效果如下:

Flutter如何利用Canvas模擬實現微信紅包領取效果

最后在金幣點擊事件上添加一個定時器,金幣旋轉 2 秒后執行紅包開啟動畫:

void clickGold(TapUpDetails details) {
  if(checkClickGold(details.globalPosition)){
    if(angleController.isAnimating){
      stop();
    }else{
      angleController.repeat(reverse: true);
      tickerProvider.setState(() {
        showOpenText = false;
      });
      timer = Timer(const Duration(seconds: 2), (){
        stop();
      });
    }
  }
}
void stop() async{
  if(angleController.isAnimating){  
    ///停止金幣動畫,讓動畫看起來更自然
    if(angleController.status == AnimationStatus.forward){
      await angleController.forward();
      angleController.reverse();
    }else if(angleController.status == AnimationStatus.reverse){
      angleController.reverse();
    }

    tickerProvider.setState(() {
      showOpenBtn = false;
    });
    translateController.forward();
  }
}

這樣就實現了點擊金幣后,金幣旋轉 2 秒后開啟紅包。

結果彈出

結果頁是一個新的界面,在紅包開啟時同步執行,并且擁有一個漸變動畫,路由跳轉時添加動畫實現,代碼如下:

void onOpen(){
  Navigator.push(
    context,
    PageRouteBuilder(
      transitionDuration: const Duration(seconds: 1),
      pageBuilder: (context, animation, secondaryAnimation) =>
      FadeTransition(
        opacity: animation,
        child: const ResultPage(),
      )
    )
  );
}

RedPacket 添加一個紅包開啟時的回調和紅包動畫完成時的回調,前者用于跳轉結果頁,后者用于移除 Overlay

OverlayEntry? entry;
void showRedPacket(BuildContext context, Function? onOpen){
  entry = OverlayEntry(builder: (context) => RedPacket(onFinish: _removeRedPacket, onOpen: onOpen,));
  Overlay.of(context)?.insert(entry!);
}

void _removeRedPacket(){
  entry?.remove();
  entry = null;
}

在金幣旋轉動畫停止時調用:

void stop() async{
  if(angleController.isAnimating){  
   /// ...
    translateController.forward();
    onOpen?.call();
  }
}

紅包動畫完成時調用 onFinish 回調, 給紅包最后的平移動畫添加監聽來實現:

translateController.addStatusListener((status) {
  if(status == AnimationStatus.completed){
    onFinish?.call();
  }
});

OK,大功告成,再看看最終的效果:

Flutter如何利用Canvas模擬實現微信紅包領取效果

關于“Flutter如何利用Canvas模擬實現微信紅包領取效果”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“Flutter如何利用Canvas模擬實現微信紅包領取效果”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

隆德县| 宜宾县| 西畴县| 德昌县| 柳林县| 麻阳| 阳春市| 鹰潭市| 宜阳县| 泾川县| 梓潼县| 容城县| 醴陵市| 临潭县| 鄂托克前旗| 葵青区| 丹寨县| 广州市| 威远县| 淮滨县| 龙山县| 常宁市| 桐梓县| 新津县| 廉江市| 桐乡市| 额尔古纳市| 焦作市| 资讯| 商都县| 聂荣县| 穆棱市| 邵东县| 南阳市| 广河县| 苏尼特右旗| 新营市| 漳浦县| 平果县| 综艺| 广平县|