亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Flutter實(shí)現(xiàn)牛頓擺動(dòng)畫效果的示例代碼

 更新時(shí)間:2022年04月25日 08:46:01   作者:老李code  
牛頓擺大家應(yīng)該都不陌生,也叫碰碰球、永動(dòng)球(理論情況下),那么今天我們用Flutter實(shí)現(xiàn)這么一個(gè)理論中的永動(dòng)球,可以作為加載Loading使用,需要的可以參考一下

前言

牛頓擺大家應(yīng)該都不陌生,也叫碰碰球、永動(dòng)球(理論情況下),那么今天我們用Flutter實(shí)現(xiàn)這么一個(gè)理論中的永動(dòng)球,可以作為加載Loading使用。

- 知識點(diǎn):繪制、動(dòng)畫曲線、多動(dòng)畫狀態(tài)更新

效果圖:

實(shí)現(xiàn)步驟

1、繪制靜態(tài)效果

首先我們需要把線和小圓球繪制出來,對于看過我之前文章的小伙伴來說這個(gè)就很簡單了,效果圖:

關(guān)鍵代碼:

// 小圓球半徑
double radius = 6;

/// 小球圓心和直線終點(diǎn)一致
//左邊小球圓心
Offset offset = Offset(20, 60);
//右邊小球圓心
Offset offset2 = Offset(20 * 6 * 8, 60);

Paint paint = Paint()
  ..color = Colors.black87
  ..strokeWidth = 2;

/// 繪制線
canvas.drawLine(Offset.zero, Offset(90, 0), paint);
canvas.drawLine(Offset(20, 0), offset, paint);
canvas.drawLine(
    Offset(20 + radius * 2, 0), Offset(20 + radius * 2, 60), paint);
canvas.drawLine(
    Offset(20 + radius * 4, 0), Offset(20 + radius * 4, 60), paint);
canvas.drawLine(
    Offset(20 + radius * 6, 0), Offset(20 + radius * 6, 60), paint);
canvas.drawLine(Offset(20 + radius * 8, 0), offset2, paint);

/// 繪制小圓球
canvas.drawCircle(offset, radius, paint);
canvas.drawCircle(Offset(20 + radius * 2, 60), radius, paint);
canvas.drawCircle(Offset(20 + radius * 4, 60), radius, paint);
canvas.drawCircle(Offset(20 + radius * 6, 60), radius, paint);
canvas.drawCircle(offset2, radius, paint);

2、加入動(dòng)畫

思路: 我們可以看到5個(gè)小球一共2個(gè)小球在運(yùn)動(dòng),左邊小球運(yùn)動(dòng)一個(gè)來回之后傳遞給右邊小球,右邊小球開始運(yùn)動(dòng),右邊一個(gè)來回再傳遞給左邊開始,也就是左邊運(yùn)動(dòng)周期是:0-1-0,正向運(yùn)動(dòng)一次,反向再運(yùn)動(dòng)一次,這樣就是一個(gè)周期,右邊也是一樣,左邊運(yùn)動(dòng)完傳遞給右邊,右邊運(yùn)動(dòng)完傳遞給左邊,這樣就簡單實(shí)現(xiàn)了牛頓擺的效果。

兩個(gè)關(guān)鍵點(diǎn)

小球運(yùn)動(dòng)路徑: 小球的運(yùn)動(dòng)路徑是一個(gè)弧度,以豎線的起點(diǎn)為圓心,終點(diǎn)為半徑,那么我們只需要設(shè)置小球運(yùn)動(dòng)至最高點(diǎn)的角度即可,通過角度就可計(jì)算出小球的坐標(biāo)點(diǎn)。

運(yùn)動(dòng)曲線: 當(dāng)然我們知道牛頓擺小球的運(yùn)動(dòng)曲線并不是勻速的,他是有一個(gè)加速減速過程的,撞擊之后,小球先加速然后減速達(dá)到最高點(diǎn)速度為0,之后速度再從0慢慢加速進(jìn)行撞擊小球,周而復(fù)始。

下面的運(yùn)動(dòng)曲線就是先加速再減速,大概符合牛頓擺的運(yùn)動(dòng)曲線。我們就使用這個(gè)曲線看看效果。

完整源碼

class OvalLoading extends StatefulWidget {
  const OvalLoading({Key? key}) : super(key: key);

  @override
  _OvalLoadingState createState() => _OvalLoadingState();
}

class _OvalLoadingState extends State<OvalLoading>
    with TickerProviderStateMixin {
  // 左邊小球
  late AnimationController _controller =
      AnimationController(vsync: this, duration: Duration(milliseconds: 300))
        ..addStatusListener((status) {
          if (status == AnimationStatus.completed) {
            _controller.reverse(); //反向執(zhí)行 1-0
          } else if (status == AnimationStatus.dismissed) {
            _controller2.forward();
          }
        })
        ..forward();
  // 右邊小球
  late AnimationController _controller2 =
      AnimationController(vsync: this, duration: Duration(milliseconds: 300))
        ..addStatusListener((status) {
          // dismissed 動(dòng)畫在起始點(diǎn)停止
          // forward 動(dòng)畫正在正向執(zhí)行
          // reverse 動(dòng)畫正在反向執(zhí)行
          // completed 動(dòng)畫在終點(diǎn)停止
          if (status == AnimationStatus.completed) {
            _controller2.reverse(); //反向執(zhí)行 1-0
          } else if (status == AnimationStatus.dismissed) {
            // 反向執(zhí)行完畢左邊小球執(zhí)行
            _controller.forward();
          }
        });
  late var cure =
      CurvedAnimation(parent: _controller, curve: Curves.easeOutCubic);
  late var cure2 =
      CurvedAnimation(parent: _controller2, curve: Curves.easeOutCubic);

  late Animation<double> animation = Tween(begin: 0.0, end: 1.0).animate(cure);

  late Animation<double> animation2 =
      Tween(begin: 0.0, end: 1.0).animate(cure2);

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsetsDirectional.only(top: 300, start: 150),
      child: CustomPaint(
        size: Size(100, 100),
        painter: _OvalLoadingPainter(
            animation, animation2, Listenable.merge([animation, animation2])),
      ),
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    _controller2.dispose();
    super.dispose();
  }
}

class _OvalLoadingPainter extends CustomPainter {
  double radius = 6;
  final Animation<double> animation;
  final Animation<double> animation2;
  final Listenable listenable;

  late Offset offset; // 左邊小球圓心
  late Offset offset2; // 右邊小球圓心

  final double lineLength = 60; // 線長

  _OvalLoadingPainter(this.animation, this.animation2, this.listenable)
      : super(repaint: listenable) {
    offset = Offset(20, lineLength);
    offset2 = Offset(20 * radius * 8, lineLength);
  }

  // 擺動(dòng)角度
  double angle = pi / 180 * 30; // 30°

  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..color = Colors.black87
      ..strokeWidth = 2;

    // 左邊小球 默認(rèn)坐標(biāo) 下方是90度 需要+pi/2
    var dx = 20 + 60 * cos(pi / 2 + angle * animation.value);
    var dy = 60 * sin(pi / 2 + angle * animation.value);
    // 右邊小球
    var dx2 = 20 + radius * 8 - 60 * cos(pi / 2 + angle * animation2.value);
    var dy2 = 60 * sin(pi / 2 + angle * animation2.value);

    offset = Offset(dx, dy);
    offset2 = Offset(dx2, dy2);

    /// 繪制線
      canvas.drawLine(Offset.zero, Offset(90, 0), paint);
    canvas.drawLine(Offset(20, 0), offset, paint);
    canvas.drawLine(
        Offset(20 + radius * 2, 0), Offset(20 + radius * 2, 60), paint);
    canvas.drawLine(
        Offset(20 + radius * 4, 0), Offset(20 + radius * 4, 60), paint);
    canvas.drawLine(
        Offset(20 + radius * 6, 0), Offset(20 + radius * 6, 60), paint);
    canvas.drawLine(Offset(20 + radius * 8, 0), offset2, paint);

    /// 繪制球
    canvas.drawCircle(offset, radius, paint);
    canvas.drawCircle(
        Offset(20 + radius * 2, 60),
        radius,
        paint);

    canvas.drawCircle(Offset(20 + radius * 4, 60), radius, paint);
    canvas.drawCircle(Offset(20 + radius * 6, 60), radius, paint);
    canvas.drawCircle(offset2, radius, paint);
  }
  @override
  bool shouldRepaint(covariant _OvalLoadingPainter oldDelegate) {
    return oldDelegate.listenable != listenable;
  }
}

去掉線的效果

總結(jié)

本文展示了實(shí)現(xiàn)牛頓擺的原理,其實(shí)并不復(fù)雜,關(guān)鍵點(diǎn)就是小球的運(yùn)動(dòng)軌跡和運(yùn)動(dòng)速度曲線,如果用到項(xiàng)目中當(dāng)做Loading還有很多優(yōu)化的空間,比如加上小球影子、修改小球顏色或者把小球換成好玩的圖片等等操作會看起來更好看一點(diǎn)

到此這篇關(guān)于Flutter實(shí)現(xiàn)牛頓擺動(dòng)畫效果的示例代碼的文章就介紹到這了,更多相關(guān)Flutter牛頓擺動(dòng)畫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論