日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何利用 Flutter 实现炫酷的 3D 卡片和帅气的 360° 展示效果

發布時間:2023/12/10 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何利用 Flutter 实现炫酷的 3D 卡片和帅气的 360° 展示效果 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本篇將帶你在 Flutter 上快速實現兩個炫酷的動畫特效,希望最后的效果可以驚艷到你。

這次靈感的來源于更新 MIUI 13 時剛好看到的卡片效果,其中除了卡片會跟隨手勢出現傾斜之外,內容里的部分文本和綠色圖標也有類似懸浮的視差效果,恰逢此時靈機一動,我們也來用 Flutter 快速實現炫酷的 3D 視差卡片,最后再拓展實現一個支持帥氣的 360° 展示的卡片效果

既然需要卡片跟隨手勢產生不規則形變,我們第一個想到的肯定是矩陣變換,在 Flutter 里我們可以使用 Matrix4 配合 Transform 來實現矩陣變換效果。

開始之前,首先我們創建用 Transform 嵌套一個 GestureDetector ,并繪制出一個 300x400 的圓角卡片,用于后續進行矩陣變換處理。

Transform(transform: Matrix4.identity(),child: GestureDetector(child: Container(width: 300,height: 400,padding: EdgeInsets.all(20),decoration: BoxDecoration(color: Colors.blueGrey,borderRadius: BorderRadius.circular(20),),),), );

接著,如下代碼所示,因為我們需要卡片跟隨手勢進行矩陣變換,所以我們可以直接在 GestureDetector 的 onPanUpdate 里獲取到手勢信息,例如 localPosition 位置信息,然后把對應的 dx 和 dy賦值到 Matrix4 的 rotateX 和 rotateY 上實現旋轉。

child: Transform(transform: Matrix4.identity()..rotateX(touchY)..rotateY(touchX),alignment: FractionalOffset.center,child: GestureDetector(onPanUpdate: (details) {setState(() {touchX = details.localPosition.dx;touchY = details.localPosition.dy;});},child: Container(

這里有個需要注意的是:上面代碼里 rotateX 使用的是 touchY ,而 rotateY 使用的是 touchX ,為什么要這樣做呢?

??舉個例子,當我們手指左右移動時,是希望卡片可以圍繞 Y 軸進行旋轉,所以我們會把 touchX 傳遞給了 rotateY ,同樣 touchY 傳遞給 rotateX 也是一個道理。

但是當我們實際運行上述代碼之后,如下圖所示,可以看到基本上我們只是稍微移動手指,卡片就會陷入瘋狂旋轉的情況,并且實際的旋轉速度會比 GIF 里快很多。

問題的原因其實是因為 rotateX 和 rotateY 需要的是一個 angle 參數,假設這里對 rotateX 和 rotateY 設置 pi / 4 ,就可以看到卡片在 X 軸和 Y 軸上都產生了 45 度的旋轉效果。

Transform(transform: Matrix4.identity()..rotateX(pi / 4)..rotateY(pi / 4),alignment: FractionalOffset.center,

所以如果直接使用手勢的 localPosition 作用于 Matrix4 肯定是不行的,我們首先需要對手勢數據進行一個采樣,因為代碼里我們設置了 FractionalOffset.center ,所以我們可以用卡片的中心點來計算手指位置,再進行壓縮處理

如下代碼所示,我們通過以卡片中心點為原點進行計算,其中 / 2 就是得到卡片的中心點,/ 100 是對數據進行壓縮采樣,但是為什么 touchX 和 touchY 的計算方式是相反的呢?

touchX = (cardWidth / 2 - details.localPosition.dx) / 100; touchY = (details.localPosition.dy - cardHeight / 2 ) / 100;

如下圖所示,因為在設置 rotateX 和 rotateY 時,賦予 > 0 的數據時卡片就會以圖片中的方向進行旋轉,由于我們是需要手指往哪邊滑動,卡片就往哪邊傾斜,所以:

  • 當我們往左水平滑動時,需要卡片往左邊傾斜,也就是圖中繞 Y 軸轉動的 >0 的方向,并且越靠近左邊需要正向的 Angle 數值越大,由于此時 localPosition.dx 是越往左越小,所以需要利用 CardWidth / 2 - details.localPosition.dx 進行計算,得到越往左有越大的正向 Angle 數值
  • 同理,當我們往下滑動時,需要卡片往下邊傾斜,也就是圖中繞 X 軸轉動的 >0 的方向,并且越靠近下邊需要正向 Angle 數值越大,由于此時 localPosition.dy 越往下越大,所以使用 details.localPosition.dy - cardHeight / 2 去計算得到正確數據

如果覺得太抽象,可以結合上邊右側的動圖,和大家買股票一樣,圖中顯示紅色時是正數,顯示綠色時是負數,可以看到:

  • 手指往左移動時,第一行 TouchX 是紅色正數,被設置給 rotateY , 然后卡片繞 Y 軸正方向旋轉
  • 手指往下移動時,第二行 TouchY 是紅色正數,被設置給 rotateX , 然后卡片繞 X 軸正方向旋轉

到這里我們就初步實現了卡片跟隨手機旋轉的效果,但是這時候的立體旋轉效果看起來其實“很別扭”,總感覺差了點什么,其實這是因為卡片在旋轉時沒有產生視覺上的深度感知

所以我們可以通過矩陣的透視變換調整視覺效果,而為了在 Z 方向實現深度感知,我們需要在矩陣中配置 .setEntry(3, 2, 0.001) ,這里的 3 表示第 3 列,2 表示第 2 行,因為是從 0 開始排列,所以也就是圖片中 Z 的位置。

其實 .setEntry(3, 2, 0.001) 就是調整 Z 軸的視角,而在 Z 上的 0.001 就是需要的透視效果測量值,類似于相機上的對焦點進行放大和縮小的作用,這個數字越大就會讓交點處看起來好像離你視覺更近,所以最終代碼如下

Transform(transform: Matrix4.identity()..setEntry(3, 2, 0.001)..rotateX(touchY)..rotateY(touchX),alignment: FractionalOffset.center,

運行之后,可以看到在增加了 Z 角度的視角調整之后,這時候看起來的立體效果就好了很多,并且也有了類似 3D 空間的感覺。

接著我們在卡片上放上一個添加一個 13 的 Text 文本,運行之后可以看到此時文本是跟隨卡片發生變化,而接下來我們需要做的,就是通過另外一個 Transform 來讓 Text 文本和卡片之間產生視差,從而出現懸浮的效果

所以接下來需要給文本內容設置一個 translate 的 Matrix4 ,讓它向著傾斜角度的相反方向移動,然后對前面的 touchX 和 touchY 進行放大,然后再通過 - 10 操作來產生一個位差。

Transform(transform: Matrix4.identity()..translate(touchX * 100 - 10,touchY * 100 - 10, 0.0),

-10 這個是我隨意寫的,你也可以根據自己的需求調節。

例如,這時候當卡片往左傾斜時,文字就會向右移動,從而產生視覺差的效果,得到類似懸浮的感覺。

完成這一步之后,接下來可以我們對文本內容進行一下美化處理,例如增加漸變顏色,添加陰影,更換字體,目的是讓字體看起來更加具備立體的效果,這里使用的 shader ,也可以讓文字在移動過程中出現不同角度的漸變效果

最后,我們還需要對卡片旋轉進行一個范圍約束,這里主要是通過卡片大小比例:

  • 在 onPanUpdate 時對 touchX 和 touchY 進行范圍約束,從而約束的卡片的傾斜角度
  • 增加了 startTransform 標志位,用于在 onTapUp 或者 onPanEnd 之后,恢復卡片回到默認狀態的作用。
Transform(transform: Matrix4.identity()..setEntry(3, 2, 0.001)..rotateX(startTransform ? touchY : 0.0)..rotateY(startTransform ? touchX : 0.0),alignment: FractionalOffset.center,child: GestureDetector(onTapUp: (_) => setState(() {startTransform = false;}),onPanCancel: () => setState(() => startTransform = false),onPanEnd: (_) => setState(() {startTransform = false;}),onPanUpdate: (details) {setState(() => startTransform = true);///y軸限制范圍if (details.localPosition.dx < cardWidth * 0.55 &&details.localPosition.dx > cardWidth * 0.3) {touchX = (cardWidth / 2 - details.localPosition.dx) / 100;}///x軸限制范圍if (details.localPosition.dy > cardHeight * 0.4 &&details.localPosition.dy < cardHeight * 0.6) {touchY = (details.localPosition.dy - cardHeight / 2) / 100;}},child:

到這里,我們只需要在全局再進行一些美化處理,運行之后就會如下圖所示,在配合陰影和漸變效果,整體的視覺立體感會更強烈,此時我們基本就實現了一開始想要的功能,

完整代碼可見: card_perspective_demo_page.dart

Web 體驗地址,PC 端記得開 Chrome 手機模式: 3D 視差卡片 。

那有人可能就想問了: 學會了這個我們還可以實現什么?

舉個例子,比如我們可以實現一個 “偽3D” 的 360° 卡片效果,利用堆疊實現立體的電子銀行卡效果。

依舊是前面的手勢旋轉邏輯,只是這里我們可以把具有前后畫面的銀行卡圖片,通過 IndexedStack 嵌套起來,嵌套之后主要是根據旋轉角度來調整 IndexedStack 里需要展示的圖片,然后利用透視旋轉來實現類似 3D 物體的 360° 旋轉展示

這里的關鍵是通過手勢旋轉角度,判斷當前需要展示 IndexedStack 里的哪個卡片,因為 Flutter 使用的 Skia 是 2D 渲染引擎,如果沒有這部分邏輯,你就只會看到單張圖片畫面的旋轉效果。

if (touchX.abs() % (pi * 3 / 2) >= pi / 2 ||touchY.abs() % (pi * 3 / 2) >= pi / 2) {showIndex = 0; } else {showIndex = 1; }

運行效果如下圖所示,可以看到在視差和圖片切換的作用下,我們用很低的成本在 Flutter 上實現了 “偽3D” 的卡片的 360° 展示,類似的實現其實還可以用于一些商品展示或者頁面切換的場景,本質上就是利用視差的效果,在 2D 屏幕上模擬現實中的畫面效果,從而達到類似 3D 的視覺作用

最后我們只需要用 Text 在卡片上添加“模擬”凹凸的文字,就實現了我們現實中類似銀行卡的卡面效果

完整代碼可見: card_3d_demo_page.dart

Web 體驗地址,PC 端記得開 chrome 手機模式: 360° 可視化 3D 電子銀行卡

好了,本篇動畫特效就到為止,如果你有什么想法,歡迎留言評論*

總結

以上是生活随笔為你收集整理的如何利用 Flutter 实现炫酷的 3D 卡片和帅气的 360° 展示效果的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。