摘要:多帶帶來看一個(gè)雨滴動(dòng)畫,其實(shí)就是一個(gè)圓圈慢慢的變大同時(shí)慢慢的變淺,最后消失。如要要做一個(gè)新的,官方建議是通過組合來實(shí)現(xiàn)。手勢(shì)識(shí)別上述基本實(shí)現(xiàn)了多個(gè)雨滴的展示和動(dòng)畫,然后我們要來實(shí)現(xiàn)對(duì)用戶點(diǎn)擊的響應(yīng)。
本文由云+社區(qū)發(fā)表目的
寫了幾個(gè)Flutter的demo,但是對(duì)Flutter的自定義view和動(dòng)畫都不太了解,看到一個(gè)類似效果在android的實(shí)現(xiàn),就嘗試用Flutter做一下。同時(shí)也是學(xué)習(xí)Flutter的自定義view和動(dòng)畫相關(guān)的知識(shí)。
效果效果動(dòng)圖
在藍(lán)色區(qū)域點(diǎn)擊,會(huì)產(chǎn)品水波紋動(dòng)畫。
宛如水珠落在池塘,雨滴落在青青草地~思路
動(dòng)畫很簡(jiǎn)單,雖然有多個(gè)雨滴,不過每次點(diǎn)擊都是重復(fù)的動(dòng)畫,所以只用管一個(gè)雨滴動(dòng)畫是怎么實(shí)現(xiàn)的,其他的都是重復(fù)。
多帶帶來看一個(gè)雨滴動(dòng)畫,其實(shí)就是一個(gè)圓圈慢慢的變大同時(shí)慢慢的變淺,最后消失。
所以我們封裝一套上述的動(dòng)畫邏輯,然后在用戶每次點(diǎn)擊時(shí)生成一個(gè)相應(yīng)的動(dòng)畫即可。
實(shí)現(xiàn) 自定義view首先我們要解決的是自定義view的問題,我們知道Flutter中的一起UI皆Flutter,但是不同于android中的View會(huì)直接提供一個(gè)draw方法讓你做自由的繪制操作。在Flutter中,除了StatefuleWidget等申明了支持繼承的類外,其他的都是不建議繼承重寫的。如要要做一個(gè)新的Widget,官方建議是通過組合Widget來實(shí)現(xiàn)。
當(dāng)然對(duì)于我們這里這種需要自己做繪制操作的,就不是組合可以解決的了,這種情況下,F(xiàn)lutter提供了CustomPainter類,這個(gè)類提供了paint方法,可以通過重寫該方法,實(shí)現(xiàn)對(duì)canvas的繪制。然后作為CustomPaint的參數(shù),控制該Widget的展示樣式。
這里由于主要的繪制是水紋,要實(shí)現(xiàn)多個(gè)重復(fù)動(dòng)畫,所以具體的繪制邏輯封裝了起來
class RainDrop extends CustomPainter { RainDrop(this.rainList); List水紋圈的繪制rainList = List(); // 雨點(diǎn)列表 Paint _paint = new Paint()..style = PaintingStyle.stroke; // 配置畫筆 @override void paint(Canvas canvas, Size size) { rainList.forEach((item) { item.drawRainDrop(canvas, _paint); // 實(shí)際的繪制邏輯 }); rainList.removeWhere((item) { // 移出無效對(duì)象 return !item.isValid(); }); } // ... }
每一個(gè)水紋的動(dòng)畫都是一樣的,所以統(tǒng)一封裝了起來。
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會(huì)把canvas傳過來,在這里完成單個(gè)水紋的繪制工作。
注釋(2)處,每個(gè)水紋圈需要確定的是位置,只要位置就行了,大小是隨著時(shí)間均勻擴(kuò)大的,給默認(rèn)起始值就行。
注釋(3)處,透明度是隨著半徑擴(kuò)大而逐漸透明的,這里簡(jiǎn)單的做了線性的映射。
注釋(4)處,繪制水紋圈,然后讓水紋半徑自增,實(shí)現(xiàn)每次繪制擴(kuò)大的效果。
注釋(5)處,給定失效的條件。超過一定半徑這個(gè)水紋就消失了。
擴(kuò)散動(dòng)畫Flutter中提供了很多的動(dòng)畫實(shí)現(xiàn),這里用到的是AnimationController。
其實(shí)AnimationController在這里就是提供了一個(gè)回調(diào),每次收到vsync信號(hào)時(shí)回調(diào)做一次更新。
_animation = new AnimationController( // 因?yàn)槭莚epeat的,這里的duration其實(shí)不care duration: const Duration(milliseconds: 200), vsync: this) ..addListener(() { if (_rainList.isEmpty) { //(1) _animation.stop(); } setState(() {}); });
這里的動(dòng)畫是通過repeat啟動(dòng)的,所以不用太關(guān)心duration,因?yàn)橹灰皇謩?dòng)關(guān)閉實(shí)際上是會(huì)一直回調(diào)的。
vsync設(shè)置的是當(dāng)前的widget,提供了一個(gè)ticker,會(huì)定時(shí)回調(diào)。然后在回調(diào)中setState讓當(dāng)前widget更新UI。
注釋(1)處是動(dòng)畫停止的條件判斷,當(dāng)每次點(diǎn)擊往_rainList中加一個(gè)對(duì)象,每個(gè)對(duì)象繪制會(huì)判斷大小是否有效,如果無效會(huì)被從列表中移出,當(dāng)列表中沒有元素時(shí)就停止動(dòng)畫。
手勢(shì)識(shí)別上述基本實(shí)現(xiàn)了多個(gè)雨滴的展示和動(dòng)畫,然后我們要來實(shí)現(xiàn)對(duì)用戶點(diǎn)擊的響應(yīng)。
Flutter提供了GestureDetector這個(gè)widget來做手勢(shì)識(shí)別。所以我們只需要用這個(gè)widget wrap住我們的自定義view,然后實(shí)現(xiàn)對(duì)應(yīng)的手勢(shì)監(jiān)聽方法即可。
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), ), ),
這里我們關(guān)注用戶輕點(diǎn)后抬起的手勢(shì),這個(gè)監(jiān)聽的方法會(huì)傳入TapUpDetails參數(shù),這個(gè)參數(shù)含有抬起的位置參數(shù),但是需要注意的是,這個(gè)坐標(biāo)是全屏幕的坐標(biāo),而繪制的坐標(biāo)是widget內(nèi)的坐標(biāo),所以我們需要將這個(gè)坐標(biāo)轉(zhuǎn)換為我們widget內(nèi)的坐標(biāo)系,F(xiàn)lutter提供了這樣的一個(gè)工具方法,參考注釋(1)處的實(shí)現(xiàn)即可。
完成了坐標(biāo)換算,就可以構(gòu)建一個(gè)“雨點(diǎn)”對(duì)象,添加到List里面。然后在注釋(2)處啟動(dòng)動(dòng)畫,就可以看到我們文章開頭的動(dòng)畫效果啦~
總結(jié)Flutter的動(dòng)畫實(shí)現(xiàn)起來真的很簡(jiǎn)單,提供一個(gè)差值回調(diào),然后不停的更新即可。不過這里暫時(shí)沒有考慮性能等問題,對(duì)setState這個(gè)方法感覺還是很黑盒,不太懂Flutter具體的UI刷新原理。
后面會(huì)梳理一下這類原理知識(shí),否則還是有點(diǎn)擔(dān)憂復(fù)雜動(dòng)畫按這種寫法是否會(huì)卡頓。
此文已由作者授權(quán)騰訊云+社區(qū)發(fā)布
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/100462.html
摘要:簡(jiǎn)介在上看到一個(gè)做的下雨效果動(dòng)畫,感覺蠻有意思的。讓瀏覽器要重繪時(shí)調(diào)用你指定的方法來繪制你的動(dòng)畫。殘影的繪制可以說是雨滴下落的關(guān)鍵。用來繪制動(dòng)畫的效果確實(shí)能讓人眼前一亮,讓的視覺效果提升一大截。發(fā)動(dòng)自己的智慧,相信能做出更多奇妙的動(dòng)畫。 簡(jiǎn)介 在codepen上看到一個(gè)Canvas做的下雨效果動(dòng)畫,感覺蠻有意思的。就研究了下,這里來分享下,實(shí)現(xiàn)技巧。效果可以見下面的鏈接。 霓虹雨: h...
摘要:簡(jiǎn)介在上看到一個(gè)做的下雨效果動(dòng)畫,感覺蠻有意思的。讓瀏覽器要重繪時(shí)調(diào)用你指定的方法來繪制你的動(dòng)畫。殘影的繪制可以說是雨滴下落的關(guān)鍵。發(fā)動(dòng)自己的智慧,相信能做出更多奇妙的動(dòng)畫。轉(zhuǎn)載出處前端開發(fā)制作的下雨動(dòng)畫簡(jiǎn)介 在codepen上看到一個(gè)Canvas做的下雨效果動(dòng)畫,感覺蠻有意思的。就研究了下,這里來分享下,實(shí)現(xiàn)技巧。效果可以見下面的鏈接。 霓虹雨:http://codepen.io/nate...
摘要:說明這篇文章說如何用畫出漂亮的下雨效果,先看看最后實(shí)現(xiàn)的效果吧。 說明 這篇文章說如何用canvas畫出漂亮的下雨效果,先看看最后實(shí)現(xiàn)的效果吧。 效果圖showImg(https://segmentfault.com/img/bV8ITm?w=936&h=532); 解釋 看圖來分析下,我們需要實(shí)現(xiàn)哪些效果。1、雨滴下落效果,移動(dòng)鼠標(biāo)控制下落方向 2、雨滴下落散成小水珠,小水珠的移動(dòng)...
摘要:相對(duì)于靜態(tài)圖表,人類總是容易被動(dòng)畫和交互式圖表所吸引??梢允褂幂p松生成圖表直方圖功率譜,條形圖,錯(cuò)誤圖表,散點(diǎn)圖等。然而,也有一些方面落后于同類的庫(kù)。動(dòng)畫使用一組固定的對(duì)象。稍后將用數(shù)據(jù)對(duì)行對(duì)象進(jìn)行填充?,F(xiàn)在用將它們轉(zhuǎn)換為動(dòng)畫。 翻譯:瘋狂的技術(shù)宅https://towardsdatascience.co... showImg(https://segmentfault.com/img...
摘要:相對(duì)于靜態(tài)圖表,人類總是容易被動(dòng)畫和交互式圖表所吸引??梢允褂幂p松生成圖表直方圖功率譜,條形圖,錯(cuò)誤圖表,散點(diǎn)圖等。然而,也有一些方面落后于同類的庫(kù)。動(dòng)畫使用一組固定的對(duì)象。稍后將用數(shù)據(jù)對(duì)行對(duì)象進(jìn)行填充?,F(xiàn)在用將它們轉(zhuǎn)換為動(dòng)畫。 翻譯:瘋狂的技術(shù)宅https://towardsdatascience.co... showImg(https://segmentfault.com/img...
閱讀 1510·2021-11-22 13:52
閱讀 1325·2021-09-29 09:34
閱讀 2723·2021-09-09 11:40
閱讀 3042·2019-08-30 15:54
閱讀 1270·2019-08-30 15:53
閱讀 982·2019-08-30 11:01
閱讀 1371·2019-08-29 17:22
閱讀 1965·2019-08-26 10:57