Flutter製作一個吃豆人載入Loading
一起養成寫作習慣!這是我參與「掘金日新計劃 · 4 月更文挑戰」的第14天,點選檢視活動詳情。
- 知識點:繪製、動畫、多狀態監聽
國際慣例,先看效果圖:
- 具體效果就是吃豆人會根據吃不同顏色的豆子改變身體的顏色。
1、繪製靜態吃豆人、豆豆、眼睛
首先,我們需要將這個靜態的吃豆人繪製出來,我們可以把吃豆人看做是一個實心圓弧,豆豆和眼睛就是一個圓。
關鍵程式碼:
```dart
//畫頭
_paint
..color = color.value
..style = PaintingStyle.fill;
var rect = Rect.fromCenter(
center: Offset(0, 0), width: size.width, height: size.height);
/// 起始角度
var a = 40 / 180 * pi;
// 繪製圓弧
canvas.drawArc(rect, 0, 2 * pi - a * 2, true, _paint);
// 畫豆豆 canvas.drawOval( Rect.fromCenter( center: Offset( size.width / 2 + ddSize - angle2.value * (size.width / 2 + ddSize), 0), width: ddSize, height: ddSize), _paint..color = color2.value);
//畫眼睛 canvas.drawOval( Rect.fromCenter( center: Offset(0, -size.height / 3), width: 8, height: 8), _paint..color = Colors.black87);
``` 動畫屬性: 嘴巴的張合:通過圓弧的角度不斷改變實現,豆豆移動:從頭的右側源源不斷的有豆子向左移動,改變豆豆x軸的座標即可,接下來我們讓吃豆人動起來吧。
2、加入動畫屬性
這裡我們需要建立2個動畫控制器,一個控制頭,一個控制豆豆,我們看到因為頭部一開一合屬於動畫正向執行一次然後再反向執行一次,相當於執行了兩次,豆豆的從右邊到嘴巴只執行了一次,所以頭的執行時間是豆豆執行時間的兩倍,嘴巴一張一合才能吃豆子嘛,吃豆完畢,將豆子顏色賦值給頭改變顏色,豆子隨機獲取另一個顏色,不斷的吃豆。 這裡的繪製狀態有多種情況,嘴巴的張合、豆子的平移、顏色的改變都需要進行重新繪製,這裡我們可以使用Listenable.merge
方法來進行監聽,接受一個Listenable
陣列,可以將我們需要改變的狀態放到這個數組裡,返回一個Listenable
賦值給CustomPainter
建構函式repaint
屬性即可,然後在監聽只需判斷這個Listenable
即可。
factory Listenable.merge(List<Listenable?> listenables) = _MergingListenable;
關鍵程式碼: 動畫執行相關。
```dart
late Animation
//初始化吃豆人、豆豆顏色
ValueNotifier
// 動畫軌跡 late CurvedAnimation cure = CurvedAnimation( parent: _controller, curve: Curves.easeIn); // 動畫執行的速度軌跡 速度的變化
@override void initState() { super.initState(); animation = Tween(begin: 0.2, end: 1.0).animate(_controller) ..addStatusListener((status) { // dismissed 動畫在起始點停止 // forward 動畫正在正向執行 // reverse 動畫正在反向執行 // completed 動畫在終點停止 if (status == AnimationStatus.completed) { _controller.reverse(); //反向執行 100-0 } else if (status == AnimationStatus.dismissed) { _color.value = _color2.value; // 獲取一個隨機彩虹色 _color2.value = getRandomColor(); _controller.forward(); //正向執行 0-100 // 豆子已經被吃了 從新載入豆子動畫 _controller2.forward(from: 0); //正向執行 0-100 } }); animation2 = Tween(begin: 0.2, end: 1.0).animate(_controller2); // 啟動動畫 正向執行 _controller.forward(); // 啟動動畫 0-1迴圈執行 _controller2.forward(); // 這裡這樣重複呼叫會導致兩次動畫執行時間不一致 時間長了就不對應了 // _controller2.repeat(); }
@override void dispose() { _controller.dispose(); _controller2.dispose();
super.dispose(); }
@override Widget build(BuildContext context) { return Center( child: CustomPaint( size: Size(50, 50), painter: Pain2Painter( _color, _color2, animation, animation2, Listenable.merge([ animation, animation2, _color, ]), ddSize: 8), )); }
// 獲取一個隨機顏色
Color getRandomColor() {
Random random = Random.secure();
int randomInt = random.nextInt(6);
var colors = **繪製吃豆人原始碼:**
dart
class Pain2Painter extends CustomPainter {
final ValueNotifier
Pain2Painter( this.color, this.color2, this.angle, this.angle2, this.listenable, {this.ddSize = 6}) : super(repaint: listenable); Paint _paint = Paint();
@override void paint(Canvas canvas, Size size) { canvas.clipRect(Offset.zero & size); canvas.translate(size.width / 2, size.height / 2); // 畫豆豆 canvas.drawOval( Rect.fromCenter( center: Offset( size.width / 2 + ddSize - angle2.value * (size.width / 2 + ddSize), 0), width: ddSize, height: ddSize), _paint..color = color2.value); //畫頭 _paint ..color = color.value ..style = PaintingStyle.fill;
var rect = Rect.fromCenter(
center: Offset(0, 0), width: size.width, height: size.height);
/// 起始角度
/// angle.value 動畫控制器的值 0.2~1 0是完全閉合就是 起始0~360° 1是完全張開 起始 40°~ 280° 順時針
var a = angle.value * 40 / 180 * pi;
// 繪製圓弧
canvas.drawArc(rect, a, 2 * pi - a * 2, true, _paint);
//畫眼睛
canvas.drawOval(
Rect.fromCenter(
center: Offset(0, -size.height / 3), width: 8, height: 8),
_paint..color = Colors.black87);
canvas.drawOval( Rect.fromCenter( center: Offset(-1.5, -size.height / 3 - 1.5), width: 3, height: 3), _paint..color = Colors.white); }
@override bool shouldRepaint(covariant Pain2Painter oldDelegate) { return oldDelegate.listenable != listenable; } } ``` 至此,一個簡單的吃豆人載入Loading就完成啦。再也不要到處都是菊花轉的樣式了。。。
總結
通過這個載入Loading動畫可以重新複習下Flutter中繪製、動畫的使用的聯動使用、還有多狀態重繪機制,通過動畫還可以改變吃豆的速度和吃豆的時間運動軌跡,有興趣可以試試哦,希望這篇文章對你有所幫助,喜歡的話點個贊再走唄~
- Flutter3.7版本新增元件-Menu菜單系列介紹
- Flutter【繪製】製作一個掘金Logo元件
- Flutter【手勢&繪製】模擬紙質書籍翻頁
- Flutter【繪製&手勢】模擬紙質書翻頁2--外掛化
- Flutter【手勢&繪製】圍棋棋盤
- Flutter【手勢&繪製】手遊操縱桿移動解析
- Flutter實現訊飛線上語音合成(WebSocket流式版)
- 2022年中總結--時間過的好快
- Flutter實現訊飛線上語音聽寫(WebSocket流式版)
- Flutter更改輸入框內容,onChanged接受不到回撥?
- 【端午】會說話的粽子你見過嗎?
- Flutter入口中的runApp方法解析
- Flutter實現手勢密碼加密、解鎖
- Flutter 獲取狀態列高度等於0,為啥?
- Flutter仿網易App廣告卡片3D翻轉
- Flutter實現心碎的感覺
- Flutter實現一個牛頓擺
- Flutter實現掘金App點贊效果
- Flutter製作一個吃豆人載入Loading
- Flutter繪製之貝塞爾曲線畫一個小海豚