如何實現一個簡單的雨滴動畫?手把手告訴你

来源:https://www.cnblogs.com/qcloud1001/archive/2018/12/27/10186546.html
-Advertisement-
Play Games

本文由雲+社區發表 目的 寫了幾個Flutter的demo,但是對Flutter的自定義view和動畫都不太瞭解,看到一個類似效果在android的實現,就嘗試用Flutter做一下。同時也是學習Flutter的自定義view和動畫相關的知識。 效果 效果動圖 在藍色區域點擊,會產品水波紋動畫。 宛 ...


本文由雲+社區發表

目的

寫了幾個Flutter的demo,但是對Flutter的自定義view和動畫都不太瞭解,看到一個類似效果在android的實現,就嘗試用Flutter做一下。同時也是學習Flutter的自定義view和動畫相關的知識。

效果

img效果動圖

在藍色區域點擊,會產品水波紋動畫。

宛如水珠落在池塘,雨滴落在青青草地~

思路

動畫很簡單,雖然有多個雨滴,不過每次點擊都是重覆的動畫,所以只用管一個雨滴動畫是怎麼實現的,其他的都是重覆。

單獨來看一個雨滴動畫,其實就是一個圓圈慢慢的變大同時慢慢的變淺,最後消失。

所以我們封裝一套上述的動畫邏輯,然後在用戶每次點擊時生成一個相應的動畫即可。

實現

自定義view

首先我們要解決的是自定義view的問題,我們知道Flutter中的一起UI皆Flutter,但是不同於android中的View會直接提供一個draw方法讓你做自由的繪製操作。在Flutter中,除了StatefuleWidget等申明瞭支持繼承的類外,其他的都是不建議繼承重寫的。如要要做一個新的Widget,官方建議是通過組合Widget來實現。

當然對於我們這裡這種需要自己做繪製操作的,就不是組合可以解決的了,這種情況下,Flutter提供了CustomPainter類,這個類提供了paint方法,可以通過重寫該方法,實現對canvas的繪製。然後作為CustomPaint的參數,控制該Widget的展示樣式。

這裡由於主要的繪製是水紋,要實現多個重覆動畫,所以具體的繪製邏輯封裝了起來

class RainDrop extends CustomPainter {
  RainDrop(this.rainList);

  List<RainDropDrawer> rainList = List(); // 雨點列表
  Paint _paint = new Paint()..style = PaintingStyle.stroke; // 配置畫筆

  @override
  void paint(Canvas canvas, Size size) {
    rainList.forEach((item) {
      item.drawRainDrop(canvas, _paint); // 實際的繪製邏輯
    });
    rainList.removeWhere((item) { // 移出無效對象
      return !item.isValid();
    });
  }
  // ...
}

水紋圈的繪製

每一個水紋的動畫都是一樣的,所以統一封裝了起來。

class RainDropDrawer {
  static const double MAX_RADIUS = 30;
  double posX;
  double posY;
  double radius = 5;

  RainDropDrawer(this.posX, this.posY); // (2)

  drawRainDrop(Canvas canvas, Paint paint) { // (1)
    double opt = (MAX_RADIUS - radius) / MAX_RADIUS; // (3)
    paint.color = Color.fromRGBO(0, 0, 0, opt);
    canvas.drawCircle(Offset(posX, posY), radius, paint); // (4)
    radius += 0.5;
  }

  bool isValid() { // (5)
    return radius < MAX_RADIUS;
  }
}

註釋(1)處,上文提到的CustomPainter會把canvas傳過來,在這裡完成單個水紋的繪製工作。

註釋(2)處,每個水紋圈需要確定的是位置,只要位置就行了,大小是隨著時間均勻擴大的,給預設起始值就行。

註釋(3)處,透明度是隨著半徑擴大而逐漸透明的,這裡簡單的做了線性的映射。

註釋(4)處,繪製水紋圈,然後讓水紋半徑自增,實現每次繪製擴大的效果。

註釋(5)處,給定失效的條件。超過一定半徑這個水紋就消失了。

擴散動畫

Flutter中提供了很多的動畫實現,這裡用到的是AnimationController。

其實AnimationController在這裡就是提供了一個回調,每次收到vsync信號時回調做一次更新。

    _animation = new AnimationController(
      // 因為是repeat的,這裡的duration其實不care
        duration: const Duration(milliseconds: 200),
        vsync: this)
      ..addListener(() {
        if (_rainList.isEmpty) { //(1)
          _animation.stop();
        }
        setState(() {});
      });

這裡的動畫是通過repeat啟動的,所以不用太關心duration,因為只要不手動關閉實際上是會一直回調的。

vsync設置的是當前的widget,提供了一個ticker,會定時回調。然後在回調中setState讓當前widget更新UI。

註釋(1)處是動畫停止的條件判斷,當每次點擊往_rainList中加一個對象,每個對象繪製會判斷大小是否有效,如果無效會被從列表中移出,當列表中沒有元素時就停止動畫。

手勢識別

上述基本實現了多個雨滴的展示和動畫,然後我們要來實現對用戶點擊的響應。

Flutter提供了GestureDetector這個widget來做手勢識別。所以我們只需要用這個widget wrap住我們的自定義view,然後實現對應的手勢監聽方法即可。

      GestureDetector(
        onTapUp: (TapUpDetails tapUp) {
          RenderBox getBox = context.findRenderObject();
          var localOffset = getBox.globalToLocal(tapUp.globalPosition); // (1)

          var rainDrop = RainDropDrawer(localOffset.dx, localOffset.dy);
          _rainList.add(rainDrop);
          _animation.repeat(); // (2)
        },
        child: CustomPaint(
          painter: RainDrop(_rainList),
        ),
      ),

這裡我們關註用戶輕點後抬起的手勢,這個監聽的方法會傳入TapUpDetails參數,這個參數含有抬起的位置參數,但是需要註意的是,這個坐標是全屏幕的坐標,而繪製的坐標是widget內的坐標,所以我們需要將這個坐標轉換為我們widget內的坐標系,Flutter提供了這樣的一個工具方法,參考註釋(1)處的實現即可。

完成了坐標換算,就可以構建一個“雨點”對象,添加到List裡面。然後在註釋(2)處啟動動畫,就可以看到我們文章開頭的動畫效果啦~

總結

Flutter的動畫實現起來真的很簡單,提供一個差值回調,然後不停的更新即可。不過這裡暫時沒有考慮性能等問題,對setState這個方法感覺還是很黑盒,不太懂Flutter具體的UI刷新原理。

後面會梳理一下這類原理知識,否則還是有點擔憂複雜動畫按這種寫法是否會卡頓。

此文已由作者授權騰訊雲+社區發佈



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 背景 最近使用ELK的sentinl進行告警配置,sentinl的郵件通知支持mustache,藉此機會學習了mustache相關知識,記錄在此。 mustache的思想 mustache的核心是標簽和logic less. 標簽: 定義模板的時候,使用了{{name}}、{{ systems}}{ ...
  • 寫前端代碼,尤其是做一個前端框架的時候,經常需要及時知道代碼的大致性能,這時候如果能有個好的辦法能一直看到當前頁面的fps就好了。 整體思路是一秒有一千毫秒,先記錄當前時間作為最後一次記錄fps的時間,通過 requestAnimationFrame 回調不斷給累加fsp計數器,並且判斷上次記錄fp ...
  • 圓角,其css如下 這沒什麼難的,記憶一下即可。但是深入一下,還是很有講究的。 問題1,div寬高皆為100px,border-radius:30px,這個30px是怎麼工作的?換成50px,70px,甚至200px會有什麼反應? 答:等於一個100px的正方形,然後用半徑為30px的圓來過渡邊角, ...
  • Vue 項目在開發時運行正常,打包發佈後卻出現各種報錯,這裡整理一下遇到的問題,以備忘。 1、js 路徑問題 腳手架預設打包的路徑為絕對路徑,改為相對路徑。修改 config/index.js 中 build 節點下 assetsPublicPath,把原來 ‘/’ 改為 ‘./’ 2、img 路徑 ...
  • jQuery是什麼? jQuery是一款優秀的JavaScript庫,從命名可以看出jQuery最主要的用途就是用來做查詢(jQuery=js+Query),正如jQuery官方Logo副標題所說(write less,do more)使用jQuery能讓我們對HTML文檔遍歷和操作、事件處理、動畫 ...
  • Node.js 10已經進入LTS時代!其應用場景已經從腳手架、輔助前端開發(如SSR、PWA等)擴展到API中間層、代理層及專業的後端開發。Node.js在企業Web開發領域也日漸成熟,無論是在API中間層,還是在微服務中都得到了非常好的落地。本書將通過Web開發框架Koa2,引領你進入Node.... ...
  • 測試Mantis rest api時碰到的問題:404 Not Found. 根據文件,Mantis rest api的預設url是{{url}}/api/rest/{{controller}}。 其中{{url}}的部分是Mantis實體的base url,{{controller}}則是各api ...
  • 1、HTML代碼,如下圖: 2、jQuery代碼,如下圖: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...