Flutter?繪制風(fēng)車實(shí)現(xiàn)示例詳解
前言展示
最近源碼看得比較多,本文來畫點(diǎn)東西調(diào)節(jié)下心情,本繪制已收錄于 FlutterUnit 的繪制集錄,本文源碼可參見【windmill.dart】 。繪制內(nèi)容非常簡單,如下所示,兩個(gè)樣式的小風(fēng)車:通過這兩個(gè)小例子,可以學(xué)到:
路徑的使用
畫板的旋轉(zhuǎn)變換
動畫曲線與 Tween 的使用
風(fēng)車1

風(fēng)車2

動圖效果

1. 風(fēng)車 1 的繪制
第一個(gè)風(fēng)車非常簡單,由四個(gè) 半圓 組成,每個(gè)部分直接的關(guān)系是旋轉(zhuǎn) 90° 。如下所示, 通過 Path#addArc 添加一個(gè)半圓形的圓弧路徑。這樣就完成了一個(gè)單體:

@override
void paint(Canvas canvas, Size size) {
canvas.translate(size.width / 2, size.height / 2);
double d = size.width * 0.4;
Path path = Path()
..addArc(
Rect.fromCenter(center: Offset(d / 2, 0), width: d, height: d),
0,
pi,
);
Paint paint = Paint()..color = const Color(0xffFBBD19);
canvas.drawPath(path, paint);
}
接下來只需要在此基礎(chǔ)上,將畫板旋轉(zhuǎn) 90° 換個(gè)顏色再畫一次這個(gè)路徑即可。你可以想象一下,你在一張紙上畫了如下的黃色塊,然后把紙沿中心旋轉(zhuǎn) 90°,只要再繪制和剛才同樣的圖形即可:

canvas.rotate(pi / 2); canvas.drawPath(path, paint..color = const Color(0xff30A04C));
以此類推,畫一個(gè)轉(zhuǎn) 90° ,畫 4 此即可。如下所示,可以通過 colors 列表通過循環(huán)遍歷繪制。這樣一個(gè)簡單的小風(fēng)車就躍然紙上了,從這里可以看出,只要更改單體的路徑,即可完成不同樣式的小風(fēng)車。

List<Color> colors = const [
Color(0xffE74437), Color(0xffFBBD19),
Color(0xff3482F0), Color(0xff30A04C)
];
Paint paint = Paint();
for (Color color in colors) {
canvas.drawPath(path, paint..color=color);
canvas.rotate(pi / 2);
}
2. 風(fēng)車 2 的繪制
風(fēng)車 2 的繪制是有一定難度的,首先期望繪制是具有 矢量性 的,它會隨著 畫板 的大小自適應(yīng)尺寸。也就是說,我們繪制時(shí)使用的尺寸都要以畫布的尺寸為基準(zhǔn)。

其次,難點(diǎn)在于數(shù)據(jù)信息,這方面可以通過 PhotoShop 等軟件來量取尺寸,獲取關(guān)鍵點(diǎn)坐標(biāo),然后進(jìn)行按照比例來進(jìn)行路徑操作。好在這里只需要獲取一個(gè)單體坐標(biāo)信息,其他三個(gè)旋轉(zhuǎn)遍歷即可。

每個(gè)單體中由兩塊區(qū)域組成,分別通過路徑的點(diǎn)操作即可。在實(shí)際開發(fā)中,如果設(shè)計(jì)給了一些比較規(guī)整的圖形,需要繪制的話,也可以采用類似的方法,或者讓設(shè)計(jì)幫你量好關(guān)鍵點(diǎn)的坐標(biāo),你按比例換算即可。
@override
void paint(Canvas canvas, Size size) {
List<Color> colors = const [ Color(0xffE74437), Color(0xffFBBD19), Color(0xff3482F0), Color(0xff30A04C) ];
canvas.translate(size.width / 2, size.height / 2);
double d = size.width * 0.4;
canvas.rotate(rotate.value*2*pi);
Paint paint = Paint();
for (Color color in colors) {
Path path1 = Path()
..moveTo(0, -d * 46/203)
..lineTo(0, -d * 203/203)
..lineTo(102/203 * d, -102/203 * d)
..lineTo(12/203 * d, -12/203 * d)..close();
canvas.drawPath(path1, paint..color=color);
Path path2 = Path()
..moveTo(12/203 * d, -12/203 * d)
..lineTo(102/203 * d, -102/203 * d)
..lineTo(102/203 * d, 0 )
..lineTo(46/203 * d, 0 )..close();
canvas.drawPath(path2, paint..color=color.withOpacity(0.2));
canvas.rotate(pi / 2);
}
}
3. 旋轉(zhuǎn)動畫的處理
Flutter 中的動畫非常簡單,首先創(chuàng)建 AnimationController 作為動畫的 "驅(qū)動器";然后如需曲線變換,可以使用 CurveTween 控制數(shù)值運(yùn)動的速度,比如這里使用 Curves.easeIn 先慢后快:

class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
late final AnimationController _ctrl = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
);
late Animation<double> rotate;
@override
void initState() {
rotate = CurveTween(curve: Curves.easeIn).animate(_ctrl);
super.initState();
}
最后將 Animation<double> 對象傳入 WindmillPainter 畫板中,作為畫板繪制的驅(qū)動力,在繪制前根據(jù)數(shù)值對畫布進(jìn)行旋轉(zhuǎn)即可:

4. 旋轉(zhuǎn)動畫的圈數(shù)
可能有人發(fā)現(xiàn),這點(diǎn)一下就轉(zhuǎn)一圈,如何轉(zhuǎn)多圈呢?其實(shí)這就是一個(gè)數(shù)學(xué)問題:轉(zhuǎn)一圈是 360°,想轉(zhuǎn) n 圈,本質(zhì)上就是在規(guī)定時(shí)間內(nèi)旋轉(zhuǎn) n*360°。 這通過 Tween 是很容易實(shí)現(xiàn)的:

比如這里轉(zhuǎn) 3 圈,最核心的是通過 Tween 指定一個(gè) 補(bǔ)間 ,然后這個(gè) rotate 在動畫進(jìn)行時(shí)就會從 0 運(yùn)動到 3*2*pi。繪制時(shí)畫板旋轉(zhuǎn) rotate.value 即可。

canvas.rotate(rotate.value);
本案例已加入 FlutterUnit的繪制集錄,可在下版本更新后體驗(yàn),感謝支持 FlutterUnit。
這就是一個(gè)非常簡單的繪制與動畫結(jié)合的小例子,希望可以對剛接觸的繪制的朋友有所幫助。不僅是 Flutter 其他的框架只要有畫板,只要能有動畫驅(qū)動,都可以完成類似的繪制,更多關(guān)于Flutter 繪制風(fēng)車的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android 判斷網(wǎng)絡(luò)狀態(tài)對音頻靜音的實(shí)現(xiàn)方法
最近小編做項(xiàng)目遇到這樣的需求,需要根據(jù)當(dāng)前場景讓app變的智能,讓app根據(jù)使用者當(dāng)前網(wǎng)絡(luò)狀態(tài),自動記性靜音等操作,具體怎么實(shí)現(xiàn)呢?下面小編給大家分享實(shí)例代碼,需要的朋友參考下吧2018-10-10
Kotlin Select協(xié)程多路復(fù)用的實(shí)現(xiàn)詳解
select是Kotlin 1.6中的特性,即選擇最快的結(jié)果。select與async、Channel結(jié)合使用,可以大大提高程序的響應(yīng)速度,還可以提高程序的靈活性、擴(kuò)展性2022-09-09
Android運(yùn)用onTouchEvent自定義滑動布局
這篇文章主要為大家詳細(xì)介紹了Android運(yùn)用onTouchEvent寫一個(gè)上下滑動的布局,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
Android實(shí)現(xiàn)字母導(dǎo)航控件的示例代碼
這篇文章主要介紹了通過自定義View實(shí)現(xiàn)字母導(dǎo)航控件的示例代碼,文中的實(shí)現(xiàn)過程講解詳細(xì),對我們學(xué)習(xí)或工作有一定幫助,感興趣的可以學(xué)習(xí)一下2022-01-01
Android小部件Widget開發(fā)過程中的坑和問題小結(jié)
這篇文章主要介紹了Android小部件Widget開發(fā)過程中的坑和問題小結(jié),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
Android studio 出現(xiàn) Unsupported major.minor version 52.0解決辦法
這篇文章主要介紹了Android studio 出現(xiàn) Unsupported major.minor version 52.0解決辦法的相關(guān)資料,需要的朋友可以參考下2016-12-12

