Flutter繪制3.4邊形及多邊形漸變動(dòng)畫實(shí)現(xiàn)示例
正文
項(xiàng)目被優(yōu)化了,人也跟著被優(yōu)化了,正好趁這一個(gè)月整理整理關(guān)于flutter的一些東西。
繪制3.4邊形
先看一下效果圖:
起因是上上上上上個(gè)月瀏覽flutter的canvas相關(guān)內(nèi)容時(shí),點(diǎn)進(jìn)去一個(gè)網(wǎng)站,看到一個(gè)讓我眼前一亮的動(dòng)效:
作者用的代碼是swift的,我沒細(xì)看,不過他文章里的一句話讓我醍醐灌頂:
That is, we want the shape be asked to draw multiple times, each time with a different value for the sides parameter: 3, 3.1, 3.15, 3.2, 3.25, all the way to 4.
大意就是說我們想搞一個(gè)從三邊形到四邊形的動(dòng)畫,我們只需要畫出3.1邊形,3.2邊形,3.3邊形,一直畫到4邊形。
這句話真的讓我醍醐灌頂,因?yàn)槲铱吹竭@個(gè)動(dòng)畫,第一反應(yīng)是需要計(jì)算每個(gè)頂點(diǎn)位置,從而做出動(dòng)畫;但是這句話讓這個(gè)問題脫離了具體細(xì)節(jié),將問題抽象化,數(shù)學(xué)化。只要我們定義出分?jǐn)?shù)邊形的繪制方法,我們就可以很簡單的完成這個(gè)動(dòng)畫。
現(xiàn)在我們只要定義如何繪制分?jǐn)?shù)邊形就可以了。
整數(shù)邊形的繪制
在定義繪制分?jǐn)?shù)邊形的繪制方法之前,我們先來看整數(shù)邊形是如何繪制的:
繪制正三角形,我們會(huì)在圓上找出三等分點(diǎn),然后依次連接這三個(gè)點(diǎn),這就是正三角形的繪制方法。
而且繪制的時(shí)候我們通常會(huì)固定一個(gè)起點(diǎn),然后從這個(gè)起點(diǎn)開始等分。
分?jǐn)?shù)邊形的繪制
分?jǐn)?shù)邊形的繪制也是一樣的道理,比如3.1邊形的繪制,我們需要找到四個(gè)點(diǎn)
我們先固定一個(gè)起點(diǎn),然后從這個(gè)起點(diǎn)開始旋轉(zhuǎn)(2*pi/3.1)個(gè)弧度,這樣依次找到剩下三個(gè)點(diǎn),(因?yàn)椴皇堑确郑钥蛇@樣找下去可以找到無數(shù)個(gè)點(diǎn),但我們只需要找四個(gè)點(diǎn)),而且當(dāng)我們給到兩個(gè)很相近的分?jǐn)?shù),比如3.1和3.11時(shí),3.1邊形對(duì)應(yīng)的四個(gè)點(diǎn)和3.11對(duì)應(yīng)的四個(gè)點(diǎn),由于它們的起點(diǎn)是固定的,剩下各自的三個(gè)點(diǎn)對(duì)應(yīng)的位置都是很接近的(因?yàn)?.1和3.11對(duì)應(yīng)的弧度是很接近的),這樣一直畫到4.0邊形,就完成了從三邊形到四邊形的漸變動(dòng)畫。
具體代碼
獲取多邊形頂點(diǎn)
List<Offset> points = []; List<Offset> getPolygonPoints1(double sides) { for (int i = 0; i < sides.ceil(); i++) { double x, y; x = radius * sin(i * 2 * pi / sides); y = -radius * cos(i * 2 * pi / sides); points.add(Offset(x, y)); } return points; }
獲取到多邊形頂點(diǎn)之后我們就可以在Custompaint的paint函數(shù)中將其繪制出來:
@override void paint(Canvas canvas, Size size) { Paint paint = Paint() ..color = const Color(0xFF47484B) ..style = PaintingStyle.stroke ..strokeWidth = 1 ..isAntiAlias = true; List<Offset> points = getPolygonPoints1(progress); for (int i = 0; i < points.length; i++) { canvas.drawLine( points[i % points.length], points[(i + 1) % points.length], paint); } }
可以看到效果如下:
但是如果我想要下圖這種效果,當(dāng)邊數(shù)為奇數(shù)時(shí),頂點(diǎn)位于最上方,邊數(shù)由奇數(shù)變成偶數(shù)時(shí),最上方的頂點(diǎn)分裂成兩個(gè),類似下圖效果:
效果改進(jìn)1
想要達(dá)到這種效果,我們只需要將代碼改進(jìn)一下,不再固定起始點(diǎn),而是在邊數(shù)由奇數(shù)變?yōu)榕紨?shù)時(shí),將起始點(diǎn)的弧度由(pi / sides)漸變?yōu)?,由偶數(shù)變位奇數(shù)時(shí),起始點(diǎn)弧度由0變?yōu)?pi / sides)。
代碼如下:
List<Offset> getPolygonPoints2(double sides) { for (int i = 0; i < sides.ceil(); i++) { double x, y; if (sides.ceil() % 2 == 0) { x = radius * sin(lerpDouble(0, (pi / sides), sides - sides.floor())! + i * 2 * pi / sides); y = -radius * cos(lerpDouble(0, (pi / sides), sides - sides.floor())! + i * 2 * pi / sides); } else { x = radius * sin(lerpDouble((pi / sides), 0, sides - sides.floor())! + i * 2 * pi / sides); y = -radius * cos(lerpDouble((pi / sides), 0, sides - sides.floor())! + i * 2 * pi / sides); } points.add(Offset(x, y)); } return points; }
此時(shí)效果如下:
但是還是有些不完美,我還想讓多邊形邊數(shù)為偶數(shù)時(shí),起始點(diǎn)是從最上方的邊的中點(diǎn)一直漸變到最上方的點(diǎn),就是下面這種效果:
效果改進(jìn)2
此時(shí)我們只需要將多邊形由偶數(shù)變?yōu)槠鏀?shù)時(shí)的起始點(diǎn)改為最上方邊線的中點(diǎn)即可。 此時(shí)代碼如下:
List<Offset> getPolygonPoints(double sides) { for (int i = 0; i < sides.ceil(); i++) { double x, y; if (sides.ceil() % 2 == 0) { if (sides.ceil() == sides) { x = radius * sin((pi / sides) + i * 2 * pi / sides); y = -radius * cos((pi / sides) + i * 2 * pi / sides); } else { x = radius * sin(lerpDouble(0, (pi / sides), sides - sides.floor())! + i * 2 * pi / sides); y = -radius * cos(lerpDouble(0, (pi / sides), sides - sides.floor())! + i * 2 * pi / sides); } } else { if (sides.ceil() == sides) { x = radius * sin(i * 2 * pi / sides); y = -radius * cos(i * 2 * pi / sides); } else { // 起始點(diǎn)位置單獨(dú)計(jì)算 if (i == 0) { double startY = -radius * cos(pi / sides); double endY = -radius; x = 0; y = lerpDouble(startY, endY, sides - sides.floor())!; } else { x = radius * sin(lerpDouble((pi / sides), 0, sides - sides.floor())! + (i - lerpDouble(1, 0, sides - sides.floor())!) * 2 * pi / sides); y = -radius * cos(lerpDouble((pi / sides), 0, sides - sides.floor())! + (i - lerpDouble(1, 0, sides - sides.floor())!) * 2 * pi / sides); } } } points.add(Offset(x, y)); } return points; }
在這個(gè)基礎(chǔ)上再畫出對(duì)角線,加上縮放,就能達(dá)到我們一開始看到的最終效果了。
一些canvas的其他小demo
關(guān)于flutter canvas的其他效果,我后面會(huì)陸續(xù)分享出來,大家喜歡的話可以關(guān)注一下~
以上就是Flutter繪制3.4邊形之多邊形漸變動(dòng)畫實(shí)現(xiàn)示例的詳細(xì)內(nèi)容,更多關(guān)于Flutter繪制3.4邊形漸變動(dòng)畫的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
IOS 中NSUserDefaults讀取和寫入自定義對(duì)象的實(shí)現(xiàn)方法
這篇文章主要介紹了IOS 中NSUserDefaults讀取和寫入自定義對(duì)象的實(shí)現(xiàn)方法的相關(guān)資料,希望通過本文大家能夠理解掌握這部分內(nèi)容,需要的朋友可以參考下2017-09-09詳解iOS 計(jì)步器的幾種實(shí)現(xiàn)方式
本篇文章主要介紹了詳解iOS 計(jì)步器的幾種實(shí)現(xiàn)方式,詳細(xì)的介紹了兩種可以獲取計(jì)步數(shù)據(jù)的方法,有興趣的可以了解一下2017-08-08iOS中FMDB事務(wù)實(shí)現(xiàn)批量更新數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了iOS中FMDB事務(wù)實(shí)現(xiàn)批量更新數(shù)據(jù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11ios實(shí)現(xiàn)簡單隨便移動(dòng)的AR功能
這篇文章主要為大家詳細(xì)介紹了ios實(shí)現(xiàn)簡單隨便走的AR功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02iOS中只讓textField使用鍵盤通知的實(shí)例代碼
本文通過實(shí)例代碼給大家介紹了OS中只讓textField使用鍵盤通知的操作方法,代碼簡單易懂,非常不錯(cuò),具有參考借鑒加載,需要的的朋友參考下吧2017-07-07iOS應(yīng)用中UISearchDisplayController搜索效果的用法
這篇文章主要介紹了iOS應(yīng)用中UISearchDisplayController搜索效果的用法,包括點(diǎn)擊搜索出現(xiàn)黑條問題的解決方法,代碼基于傳統(tǒng)的Objective-C,需要的朋友可以參考下2016-02-02iOS scrollview實(shí)現(xiàn)三屏復(fù)用循環(huán)廣告
這篇文章主要介紹了iOS scrollview實(shí)現(xiàn)三屏復(fù)用循環(huán)廣告,從服務(wù)器請(qǐng)求的廣告,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01