最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(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使用。

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

效果圖:

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

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

首先我們需要把線和小圓球繪制出來(lái),對(duì)于看過(guò)我之前文章的小伙伴來(lái)說(shuō)這個(gè)就很簡(jiǎn)單了,效果圖:

關(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)畫(huà)

思路: 我們可以看到5個(gè)小球一共2個(gè)小球在運(yùn)動(dòng),左邊小球運(yùn)動(dòng)一個(gè)來(lái)回之后傳遞給右邊小球,右邊小球開(kāi)始運(yùn)動(dòng),右邊一個(gè)來(lái)回再傳遞給左邊開(kāi)始,也就是左邊運(yùn)動(dòng)周期是:0-1-0,正向運(yùn)動(dòng)一次,反向再運(yùn)動(dòng)一次,這樣就是一個(gè)周期,右邊也是一樣,左邊運(yùn)動(dòng)完傳遞給右邊,右邊運(yùn)動(dòng)完傳遞給左邊,這樣就簡(jiǎn)單實(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)的角度即可,通過(guò)角度就可計(jì)算出小球的坐標(biāo)點(diǎn)。

運(yùn)動(dòng)曲線: 當(dāng)然我們知道牛頓擺小球的運(yùn)動(dòng)曲線并不是勻速的,他是有一個(gè)加速減速過(guò)程的,撞擊之后,小球先加速然后減速達(dá)到最高點(diǎn)速度為0,之后速度再?gòu)?慢慢加速進(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)畫(huà)在起始點(diǎn)停止
          // forward 動(dòng)畫(huà)正在正向執(zhí)行
          // reverse 動(dòng)畫(huà)正在反向執(zhí)行
          // completed 動(dòng)畫(huà)在終點(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; // 線長(zhǎng)

  _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)化的空間,比如加上小球影子、修改小球顏色或者把小球換成好玩的圖片等等操作會(huì)看起來(lái)更好看一點(diǎn)

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

相關(guān)文章

  • Android高級(jí)UI特效仿直播點(diǎn)贊動(dòng)畫(huà)效果

    Android高級(jí)UI特效仿直播點(diǎn)贊動(dòng)畫(huà)效果

    這篇文章主要介紹了Android高級(jí)UI特效仿直播點(diǎn)贊動(dòng)畫(huà)效果,最近比較火的抖音快手直播視頻都有這樣的效果,下面腳本之家小編給大家?guī)?lái)android 仿直播點(diǎn)贊效果的實(shí)現(xiàn)代碼,需要的朋友參考下吧
    2018-03-03
  • android列表控件實(shí)現(xiàn)展開(kāi)、收縮功能

    android列表控件實(shí)現(xiàn)展開(kāi)、收縮功能

    這篇文章主要為大家詳細(xì)介紹了android支持展開(kāi)/收縮功能的列表控件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-11-11
  • Android 獲取drawable目錄圖片 并存入指定文件的步驟詳解

    Android 獲取drawable目錄圖片 并存入指定文件的步驟詳解

    這篇文章主要介紹了Android 獲取drawable目錄圖片 并存入指定文件,本文分步驟通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Android實(shí)現(xiàn)圖片一邊的三角形邊框效果

    Android實(shí)現(xiàn)圖片一邊的三角形邊框效果

    這篇文章主要介紹了Android實(shí)現(xiàn)圖片一邊的三角形邊框效果,本文圖文并茂通過(guò)實(shí)例代碼講解的非常詳細(xì),需要的朋友可以參考下
    2019-12-12
  • Android中父View和子view的點(diǎn)擊事件處理問(wèn)題探討

    Android中父View和子view的點(diǎn)擊事件處理問(wèn)題探討

    當(dāng)屏幕中包含一個(gè)ViewGroup,而這個(gè)ViewGroup又包含一個(gè)子view,這個(gè)時(shí)候android系統(tǒng)如何處理Touch事件呢,接下來(lái)將對(duì)此問(wèn)題進(jìn)行深入了解,感興趣的朋友可以了解參考下,或許對(duì)你有所幫助
    2013-01-01
  • Android之TextView自適應(yīng)大小

    Android之TextView自適應(yīng)大小

    對(duì)于設(shè)置TextView的字體默認(rèn)大小對(duì)于UI界面的好看程度是很重要的,小屏幕設(shè)置的文字過(guò)大或者大屏幕設(shè)置的文字過(guò)小都造成UI的不美觀?,F(xiàn)在就讓我們學(xué)習(xí)自適應(yīng)大小的TextView控件。下面跟著小編一起來(lái)看下吧
    2017-03-03
  • Android仿QQ好友詳情頁(yè)下拉頂部圖片縮放效果

    Android仿QQ好友詳情頁(yè)下拉頂部圖片縮放效果

    這篇文章主要為大家詳細(xì)介紹了Android仿QQ好友詳情頁(yè)下拉頂部圖片縮放效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • Android后端服務(wù)器的搭建方法

    Android后端服務(wù)器的搭建方法

    本篇文章主要介紹了Android后端服務(wù)器的搭建方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • Android 修改現(xiàn)有ROM資源文件如何實(shí)現(xiàn)

    Android 修改現(xiàn)有ROM資源文件如何實(shí)現(xiàn)

    這篇文章主要介紹了Android 修改現(xiàn)有ROM資源文件如何實(shí)現(xiàn)的相關(guān)資料,這里對(duì)修改ROM 文件進(jìn)行了詳細(xì)的步驟介紹,需要的朋友可以參考下
    2016-12-12
  • Android開(kāi)發(fā)優(yōu)化之Apk瘦身優(yōu)化指南

    Android開(kāi)發(fā)優(yōu)化之Apk瘦身優(yōu)化指南

    隨著業(yè)務(wù)快速發(fā)展,各種業(yè)務(wù)功能上線,版本不斷迭代,apk體積也越來(lái)越大,下面這篇文章主要給大家介紹了關(guān)于Android開(kāi)發(fā)優(yōu)化之Apk瘦身優(yōu)化的相關(guān)資料,需要的朋友可以參考下
    2022-05-05

最新評(píng)論

睢宁县| 咸宁市| 临猗县| 乌苏市| 兴仁县| 时尚| 上饶县| 吐鲁番市| 佛学| 新宁县| 青铜峡市| 绵竹市| 陇川县| 同仁县| 当雄县| 安塞县| 民丰县| 承德县| 台湾省| 苏尼特右旗| 治县。| 栾川县| 东城区| 会泽县| 永顺县| 绍兴县| 桐庐县| 三明市| 定日县| 金湖县| 革吉县| 仪征市| 峨边| 濮阳县| 勃利县| 阳原县| 东明县| 青河县| 富阳市| 扶风县| 务川|