likes
comments
collection
share

Flutter 模仿虎撲APP勳章效果(一)勳章基本運動

作者站长头像
站长
· 阅读数 4

前言

使用虎撲APP時,注意到個人頁面上的勳章展示區,勳章會隨手機的轉動而移動掉落。很喜歡這個效果,也很好奇是怎麼實現的,便想在flutter上嘗試重現出來,當作練習項目。

Flutter 模仿虎撲APP勳章效果(一)勳章基本運動

思路

在這邊大致列幾個關鍵點

  • 基本運動
  • 邊界碰撞
  • 相互碰撞
  • 球體自轉

基本運動

使用sensors_plus

我這裡選用加速度感測的監聽,ValueNotifier來觸發刷新取代setstate。

import 'package:sensors_plus/sensors_plus.dart';

ValueNotifier<List<double>> phoneXY = ValueNotifier([0, 0]);

StreamSubscription sensor = accelerometerEvents.listen((AccelerometerEvent event) {
  phoneXY.value = [event.x, event.y];
});

由於sensors_plus在安卓端適用SensorManager默認 SENSOR_DELAY_NORMAL靈敏度不高,可以手動修改套件的本地緩存,或是把sensors_plus colne下來改成私有專案(以下是兩種引用私有庫方式)。

sensors_plus:
  git:
    url: https://github.com/xxx/sensors_plus.git
    
sensors_plus:
  path: xxx/sensors_plus

定義小球

class Ball {
  //位置
  Offset position;
  //顏色
  Color color;
  //半徑
  double radius;
  //速度
  double speedX = 0;
  double speedY = 0;

  Ball({
    //給定默認色
    this.color = Colors.lightGreen,
    required this.position,
    required this.radius,
  });
}

繪製小球

先用List放入兩個小球(徽章)

List<Ball> balls = [];

balls.add(
      Ball(
        radius: 10,
        position: const Offset(100, 100),
        color: Colors.pink,
      ),
    );

balls.add(
      Ball(
        radius: 20,
        position: const Offset(100, 100),
      ),
    );

我的第一個想法是用canvas繪製,而ValueListenable可以只刷新畫布而不重構widget。 我將每次刷新都當作一個瞬間,大致把模擬移動簡化成下述公式,這樣就有了小球歲加速度計墜落移動的效果。因為每次執行paint都是一個瞬間,就可以把d時間 dt當作1來忽略。

新速度=舊速度+加速度∗d時間新速度 = 舊速度 + 加速度 * d時間新速度=舊速度+加速度d時間

d位移=新速度∗d時間d位移 = 新速度 * d時間d位移=新速度d時間

CustomPaint(
            size: size,
            painter: BallPainter(balls: balls, phoneXY: phoneXY),
),

class BallPainter extends CustomPainter {
  final List<Ball> balls;
  final ValueListenable<List<double>> phoneXY;

  BallPainter({
    required this.balls,
    required this.phoneXY,
  }) : super(repaint: phoneXY);

  final Paint _paint = Paint()..isAntiAlias = true;

  @override
  void paint(Canvas canvas, Size size) {
    for (var ball in balls) {
      //更新速度
      ball.speedX -= phoneXY.value[0] / 20;
      ball.speedY += phoneXY.value[1] / 20;

      //更新位移
      double dx = ball.speedX;
      double dy = ball.speedY;

      //🙏位置
      ball.position += Offset(dx, dy);

      _paint.color = ball.color;
      canvas.drawCircle(ball.position, ball.radius, _paint);
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    //要能夠刷新
    return true;
  }
}
Flutter 模仿虎撲APP勳章效果(一)勳章基本運動

後話

基本的運動到這邊就結束了,這些還是比較基礎的內容分享,如果文中有任何錯誤歡迎大佬們指正。

後面幾個關鍵點我還尚未解決,慢慢處理慢慢上傳,有任何想法也歡迎分享,互相參考互相學習。

參考文章

转载自:https://juejin.cn/post/7128348023028973599
评论
请登录