日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無(wú)先后,達(dá)者為師

網(wǎng)站首頁(yè) 編程語(yǔ)言 正文

Android?Flutter繪制有趣的?loading加載動(dòng)畫(huà)_Android

作者:島上碼農(nóng) ? 更新時(shí)間: 2022-09-21 編程語(yǔ)言

前言

在網(wǎng)絡(luò)速度較慢的場(chǎng)景,一個(gè)有趣的加載會(huì)提高用戶的耐心和對(duì) App 的好感,有些 loading 動(dòng)效甚至?xí)層脩粲邢肱宄麄€(gè)動(dòng)效過(guò)程到底是怎么樣的沖動(dòng)。然而,大部分的 App的 loading 就是下面這種千篇一律的效果 —— 俗稱“轉(zhuǎn)圈”。

本篇我們利用Flutter 的 PathMetric來(lái)玩幾個(gè)有趣的 loading 效果。

效果1:圓環(huán)內(nèi)滾動(dòng)的球

如上圖所示,一個(gè)紅色的小球在藍(lán)色的圓環(huán)內(nèi)滾動(dòng),而且在往上滾動(dòng)的時(shí)候速度慢,往下滾動(dòng)的時(shí)候有個(gè)明顯的加速過(guò)程。這個(gè)效果實(shí)現(xiàn)的思路如下:

  • 繪制一個(gè)藍(lán)色的圓環(huán),在藍(lán)色的圓環(huán)內(nèi)構(gòu)建一個(gè)半徑更小一號(hào)的圓環(huán)路徑(Path)。
  • 讓紅色小球在動(dòng)畫(huà)控制下沿著內(nèi)部的圓環(huán)定義的路徑運(yùn)動(dòng)。
  • 選擇一個(gè)中間減速(上坡)兩邊加速的動(dòng)畫(huà)曲線。

下面是實(shí)現(xiàn)代碼:

// 動(dòng)畫(huà)控制設(shè)置
controller =
  AnimationController(duration: const Duration(seconds: 3), vsync: this);
animation = Tween<double>(begin: 0, end: 1.0).animate(CurvedAnimation(
  parent: controller,
  curve: Curves.slowMiddle,
))
..addListener(() {
  setState(() {});
});

// 繪制和動(dòng)畫(huà)控制方法
_drawLoadingCircle(Canvas canvas, Size size) {
  var paint = Paint()..style = PaintingStyle.stroke
    ..color = Colors.blue[400]!
    ..strokeWidth = 2.0;
  var path = Path();
  final radius = 40.0;
  var center = Offset(size.width / 2, size.height / 2);
  path.addOval(Rect.fromCircle(center: center, radius: radius));
  canvas.drawPath(path, paint);
  
  var innerPath = Path();
  final ballRadius = 4.0;
  innerPath.addOval(Rect.fromCircle(center: center, radius: radius - ballRadius));
  var metrics = innerPath.computeMetrics();
  paint.color = Colors.red;
  paint.style = PaintingStyle.fill;
  for (var pathMetric in metrics) {
    var tangent = pathMetric.getTangentForOffset(pathMetric.length * animationValue);
    canvas.drawCircle(tangent!.position, ballRadius, paint);
  }
}

效果2:雙軌運(yùn)動(dòng)

上面的實(shí)現(xiàn)效果其實(shí)比較簡(jiǎn)單,就是繪制了一個(gè)圓和一個(gè)橢圓,然后讓兩個(gè)實(shí)心圓沿著路徑運(yùn)動(dòng)。因?yàn)橛辛诉@個(gè)組合效果,趣味性增加不少,外面的橢圓看起來(lái)就像是一條衛(wèi)星軌道一樣。實(shí)現(xiàn)的邏輯如下:

  • 繪制一個(gè)圓和一個(gè)橢圓,二者的中心點(diǎn)重合;
  • 在圓和橢圓的路徑上分別繪制一個(gè)小的實(shí)心圓;
  • 通過(guò)動(dòng)畫(huà)控制實(shí)心圓沿著大圓和橢圓的路徑上運(yùn)動(dòng)。

具體實(shí)現(xiàn)的代碼如下所示。

controller =
      AnimationController(duration: const Duration(seconds: 2), vsync: this);
  animation = Tween<double>(begin: 0, end: 1.0).animate(CurvedAnimation(
    parent: controller,
    curve: Curves.easeInOutSine,
  ))
    ..addListener(() {
      setState(() {});
    });

_drawTwinsCircle(Canvas canvas, Size size) {
  var paint = Paint()
    ..style = PaintingStyle.stroke
    ..color = Colors.blue[400]!
    ..strokeWidth = 2.0;

  final radius = 50.0;
  final ballRadius = 6.0;
  var center = Offset(size.width / 2, size.height / 2);
  var circlePath = Path()
    ..addOval(Rect.fromCircle(center: center, radius: radius));
  paint.style = PaintingStyle.stroke;
  paint.color = Colors.blue[400]!;
  canvas.drawPath(circlePath, paint);

  var circleMetrics = circlePath.computeMetrics();
  for (var pathMetric in circleMetrics) {
    var tangent = pathMetric
        .getTangentForOffset(pathMetric.length * animationValue);

    paint.style = PaintingStyle.fill;
    paint.color = Colors.blue;
    canvas.drawCircle(tangent!.position, ballRadius, paint);
  }

  paint.style = PaintingStyle.stroke;
  paint.color = Colors.green[600]!;
  var ovalPath = Path()
    ..addOval(Rect.fromCenter(center: center, width: 3 * radius, height: 40));
  canvas.drawPath(ovalPath, paint);
  var ovalMetrics = ovalPath.computeMetrics();

  for (var pathMetric in ovalMetrics) {
    var tangent =
        pathMetric.getTangentForOffset(pathMetric.length * animationValue);

    paint.style = PaintingStyle.fill;
    canvas.drawCircle(tangent!.position, ballRadius, paint);
  }
}

效果3:鐘擺運(yùn)動(dòng)

鐘擺運(yùn)動(dòng)的示意圖如下所示,一條繩子系著一個(gè)球懸掛某處,把球拉起一定的角度釋放后,球就會(huì)帶動(dòng)繩子沿著一條圓弧來(lái)回運(yùn)動(dòng),這條圓弧的半徑就是繩子的長(zhǎng)度。

這個(gè)效果通過(guò)代碼來(lái)實(shí)現(xiàn)的話,需要做下面的事情:

  • 繪制頂部的橫線,代表懸掛的頂點(diǎn);
  • 繪制運(yùn)動(dòng)的圓弧路徑,以便讓球沿著圓弧運(yùn)動(dòng);
  • 繪制實(shí)心圓代表球,并通過(guò)動(dòng)畫(huà)控制沿著一條圓弧運(yùn)動(dòng);
  • 用一條頂端固定,末端指向球心的直線代表繩子;
  • 當(dāng)球運(yùn)動(dòng)到弧線的終點(diǎn)后,通過(guò)動(dòng)畫(huà)反轉(zhuǎn)(reverse)控制球 返回;到起點(diǎn)后再正向(forward) 運(yùn)動(dòng)就可以實(shí)現(xiàn)來(lái)回運(yùn)動(dòng)的效果了。

具體實(shí)現(xiàn)的代碼如下,這里在繪制球的時(shí)候給 Paint 對(duì)象增加了一個(gè) maskFilter 屬性,以便讓球看起來(lái)發(fā)光,更加好看點(diǎn)。

controller =
        AnimationController(duration: const Duration(seconds: 2), vsync: this);
animation = Tween<double>(begin: 0, end: 1.0).animate(CurvedAnimation(
  parent: controller,
  curve: Curves.easeInOutQuart,
))
  ..addListener(() {
    setState(() {});
  }
  ..addStatusListener((status) {
   if (status == AnimationStatus.completed) {
     controller.reverse();
   } else if (status == AnimationStatus.dismissed) {
     controller.forward();
   }
 });

_drawPendulum(Canvas canvas, Size size) {
  var paint = Paint()
    ..style = PaintingStyle.stroke
    ..color = Colors.blue[400]!
    ..strokeWidth = 2.0;

  final ceilWidth = 60.0;
  final pendulumHeight = 200.0;
  var ceilCenter =
      Offset(size.width / 2, size.height / 2 - pendulumHeight / 2);
  var ceilPath = Path()
    ..moveTo(ceilCenter.dx - ceilWidth / 2, ceilCenter.dy)
    ..lineTo(ceilCenter.dx + ceilWidth / 2, ceilCenter.dy);
  canvas.drawPath(ceilPath, paint);

  var pendulumArcPath = Path()
    ..addArc(Rect.fromCircle(center: ceilCenter, radius: pendulumHeight),
        3 * pi / 4, -pi / 2);

  paint.color = Colors.white70;
  var metrics = pendulumArcPath.computeMetrics();

  for (var pathMetric in metrics) {
    var tangent =
        pathMetric.getTangentForOffset(pathMetric.length * animationValue);

    canvas.drawLine(ceilCenter, tangent!.position, paint);
    paint.style = PaintingStyle.fill;
    paint.color = Colors.blue;
    paint.maskFilter = MaskFilter.blur(BlurStyle.solid, 4.0);
    canvas.drawCircle(tangent.position, 16.0, paint);
  }
}

總結(jié)

本篇介紹了三種 Loading 動(dòng)效的繪制邏輯和實(shí)現(xiàn)代碼,可以看到利用路徑屬性進(jìn)行繪圖以及動(dòng)畫(huà)控制可以實(shí)現(xiàn)很多有趣的動(dòng)畫(huà)效果。

原文鏈接:https://juejin.cn/post/7125029565625270286

欄目分類
最近更新