欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Flutter制作一個(gè)吃豆人加載動(dòng)畫(huà)

 更新時(shí)間:2022年04月20日 08:46:42   作者:老李code  
這篇文章主要為大家介紹了如何利用Flutter制作出吃豆人加載動(dòng)畫(huà)效果,文中的示例代碼講解詳細(xì),快跟隨小編一起動(dòng)手嘗試一下

效果圖

國(guó)際慣例,先看效果圖:

具體效果就是吃豆人會(huì)根據(jù)吃不同顏色的豆子改變身體的顏色。

繪制靜態(tài)吃豆人、豆豆、眼睛

首先,我們需要將這個(gè)靜態(tài)的吃豆人繪制出來(lái),我們可以把吃豆人看做是一個(gè)實(shí)心圓弧,豆豆和眼睛就是一個(gè)圓。

關(guān)鍵代碼:

//畫(huà)頭
_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);

// 畫(huà)豆豆
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);

//畫(huà)眼睛
canvas.drawOval(
    Rect.fromCenter(
        center: Offset(0, -size.height / 3), width: 8, height: 8),
    _paint..color = Colors.black87);

動(dòng)畫(huà)屬性: 嘴巴的張合:通過(guò)圓弧的角度不斷改變實(shí)現(xiàn),豆豆移動(dòng):從頭的右側(cè)源源不斷的有豆子向左移動(dòng),改變豆豆x軸的坐標(biāo)即可,接下來(lái)我們讓吃豆人動(dòng)起來(lái)吧。

加入動(dòng)畫(huà)屬性

這里我們需要?jiǎng)?chuàng)建2個(gè)動(dòng)畫(huà)控制器,一個(gè)控制頭,一個(gè)控制豆豆,我們看到因?yàn)轭^部一開(kāi)一合屬于動(dòng)畫(huà)正向執(zhí)行一次然后再反向執(zhí)行一次,相當(dāng)于執(zhí)行了兩次,豆豆的從右邊到嘴巴只執(zhí)行了一次,所以頭的執(zhí)行時(shí)間是豆豆執(zhí)行時(shí)間的兩倍,嘴巴一張一合才能吃豆子嘛,吃豆完畢,將豆子顏色賦值給頭改變顏色,豆子隨機(jī)獲取另一個(gè)顏色,不斷的吃豆。 這里的繪制狀態(tài)有多種情況,嘴巴的張合、豆子的平移、顏色的改變都需要進(jìn)行重新繪制,這里我們可以使用 Listenable.merge方法來(lái)進(jìn)行監(jiān)聽(tīng),接受一個(gè)Listenable數(shù)組,可以將我們需要改變的狀態(tài)放到這個(gè)數(shù)組里,返回一個(gè) Listenable賦值給CustomPainter構(gòu)造函數(shù)repaint屬性即可,然后在監(jiān)聽(tīng)只需判斷這個(gè)Listenable即可。

factory Listenable.merge(List<Listenable?> listenables) = _MergingListenable;

關(guān)鍵代碼: 動(dòng)畫(huà)執(zhí)行相關(guān)。

late Animation<double> animation; // 吃豆人
late Animation<double> animation2; // 豆豆
late AnimationController _controller = AnimationController(
    vsync: this, duration: Duration(milliseconds: 500)); //1s
late AnimationController _controller2 = AnimationController(
    vsync: this, duration: Duration(milliseconds: 1000)); //2s

//初始化吃豆人、豆豆顏色
ValueNotifier<Color> _color = ValueNotifier<Color>(Colors.yellow.shade800);
ValueNotifier<Color> _color2 =
    ValueNotifier<Color>(Colors.redAccent.shade400);

// 動(dòng)畫(huà)軌跡
late CurvedAnimation cure = CurvedAnimation(
    parent: _controller, curve: Curves.easeIn); // 動(dòng)畫(huà)運(yùn)行的速度軌跡 速度的變化

@override
void initState() {
  super.initState();
  animation = Tween(begin: 0.2, end: 1.0).animate(_controller)
    ..addStatusListener((status) {
      // dismissed 動(dòng)畫(huà)在起始點(diǎn)停止
      // forward 動(dòng)畫(huà)正在正向執(zhí)行
      // reverse 動(dòng)畫(huà)正在反向執(zhí)行
      // completed 動(dòng)畫(huà)在終點(diǎn)停止
      if (status == AnimationStatus.completed) {
        _controller.reverse(); //反向執(zhí)行 100-0
      } else if (status == AnimationStatus.dismissed) {
        _color.value = _color2.value;
        // 獲取一個(gè)隨機(jī)彩虹色
        _color2.value = getRandomColor();
        _controller.forward(); //正向執(zhí)行 0-100
        // 豆子已經(jīng)被吃了 從新加載豆子動(dòng)畫(huà)
        _controller2.forward(from: 0); //正向執(zhí)行 0-100
      }
    });
animation2 = Tween(begin: 0.2, end: 1.0).animate(_controller2);
  // 啟動(dòng)動(dòng)畫(huà) 正向執(zhí)行
  _controller.forward();
  // 啟動(dòng)動(dòng)畫(huà) 0-1循環(huán)執(zhí)行
  _controller2.forward();
  // 這里這樣重復(fù)調(diào)用會(huì)導(dǎo)致兩次動(dòng)畫(huà)執(zhí)行時(shí)間不一致 時(shí)間長(zhǎng)了就不對(duì)應(yīng)了
  // _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),
  ));
}

// 獲取一個(gè)隨機(jī)顏色
Color getRandomColor() {
  Random random = Random.secure();
  int randomInt = random.nextInt(6);
  var colors = <Color>[
    Colors.red,
    Colors.orange,
    Colors.yellow,
    Colors.green,
    Colors.blue,
    Colors.indigo,
    Colors.purple,
  ];
  Color color = colors[randomInt];
  while (color == _color2.value) {
    // 重復(fù)再選一個(gè)
    color = colors[random.nextInt(6)];
  }
  return color;
}

繪制吃豆人源碼:

class Pain2Painter extends CustomPainter {
  final ValueNotifier<Color> color; // 吃豆人的顏色
  final ValueNotifier<Color> color2; // 豆子的的顏色
  final Animation<double> angle; // 吃豆人
  final Animation<double> angle2; // 豆
  final double ddSize; // 豆豆大小
  final Listenable listenable;

  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);
    // 畫(huà)豆豆
    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);
    //畫(huà)頭
    _paint
      ..color = color.value
      ..style = PaintingStyle.fill;

    var rect = Rect.fromCenter(
        center: Offset(0, 0), width: size.width, height: size.height);

    /// 起始角度
    /// angle.value 動(dòng)畫(huà)控制器的值 0.2~1 0是完全閉合就是 起始0~360° 1是完全張開(kāi) 起始 40°~ 280° 順時(shí)針
    var a = angle.value * 40 / 180 * pi;
    // 繪制圓弧
    canvas.drawArc(rect, a, 2 * pi - a * 2, true, _paint);
    //畫(huà)眼睛
    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;
  }
}

至此,一個(gè)簡(jiǎn)單的吃豆人加載Loading就完成啦。再也不要到處都是菊花轉(zhuǎn)的樣式了。。。

總結(jié)

通過(guò)這個(gè)加載Loading動(dòng)畫(huà)可以重新復(fù)習(xí)下Flutter中繪制、動(dòng)畫(huà)的使用的聯(lián)動(dòng)使用、還有多狀態(tài)重繪機(jī)制,通過(guò)動(dòng)畫(huà)還可以改變吃豆的速度和吃豆的時(shí)間運(yùn)動(dòng)軌跡,有興趣可以試試哦。

以上就是基于Flutter制作一個(gè)吃豆人加載動(dòng)畫(huà)的詳細(xì)內(nèi)容,更多關(guān)于Flutter加載動(dòng)畫(huà)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論