You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter AnimationController重复3次后卡顿严重,求解决方案

Flutter线条动画卡顿优化方案

1. 优化动画控制器的重复逻辑

你当前通过addListener每帧判断动画是否完成,这种方式会产生不必要的高频回调。改用addStatusListener仅在动画状态变化时处理重复逻辑,能大幅减少回调次数:

// 初始化控制器
_controller = AnimationController(
  duration: Duration(seconds: _roundDuration), 
  vsync: this
);

// 替换原addListener为addStatusListener
_controller.addStatusListener((status) {
  if (status == AnimationStatus.completed) {
    _sets--;
    if (_sets > 0) {
      _controller.reset();
      _controller.forward();
    } else {
      _controller.stop();
    }
  }
});
super.initState();

2. 复用Paint对象,避免重复创建

Paint属于开销较高的资源,你当前在paint方法内每次都重新创建,会累积性能损耗。将其改为类的静态成员复用:

class MyPainter extends CustomPainter {
  final double percentValue;
  final int moveDuration;
  final int holdDuration;
  
  // 静态复用Paint对象
  static final holdingLinePaint = Paint()
    ..strokeWidth = 40
    ..color = Colors.amber
    ..strokeCap = StrokeCap.round;

  static final linePaint = Paint()
    ..strokeWidth = 40
    ..color = Colors.red
    ..strokeCap = StrokeCap.round;
    
  // 预计算固定值,避免每帧重复计算
  final double totalDuration;
  final double firstEndX;
  final double secondEndX;

  MyPainter({
    required this.percentValue,
    required this.moveDuration,
    required this.holdDuration,
  })  : totalDuration = 2 * moveDuration + holdDuration,
        firstEndX = (380 / (2 * moveDuration + holdDuration)) * moveDuration + 10.0,
        secondEndX = (moveDuration + holdDuration) / (2 * moveDuration + holdDuration) * 380 + 10.0;

  @override
  void paint(Canvas canvas, Size size) {
    const lineLength = 380;
    const leftPadding = 10.0;
    final dy = size.height / 2;

    final lineStart = Offset(leftPadding, dy);
    final lineEnd = Offset(percentValue * 380 + leftPadding, dy);
    
    final firstEnd = Offset(firstEndX, dy);
    final secondEnd = Offset(secondEndX, dy);

    canvas.drawCircle(firstEnd, 10, Paint());
    canvas.drawCircle(secondEnd, 10, Paint());

    // 原有的阶段判断逻辑保持不变,替换Paint为静态对象
    if (percentValue < (moveDuration / totalDuration)) {
      canvas.drawLine(lineStart, lineEnd, linePaint);
    } else if (percentValue >= (moveDuration / totalDuration) &&
        percentValue < (moveDuration + holdDuration) / totalDuration) {
      canvas.drawLine(firstEnd, lineEnd, holdingLinePaint);
      canvas.drawLine(lineStart, firstEnd, linePaint);
    } else {
      canvas.drawLine(secondEnd, lineEnd, linePaint);
      canvas.drawLine(firstEnd, secondEnd, holdingLinePaint);
      canvas.drawLine(lineStart, firstEnd, linePaint); 
    }
  }

3. 精准控制重绘时机

当前shouldRepaint始终返回true,会导致每帧都强制重绘,即使参数没有变化。修改为仅在必要时触发重绘:

@override
bool shouldRepaint(covariant MyPainter oldDelegate) {
  return percentValue != oldDelegate.percentValue ||
         moveDuration != oldDelegate.moveDuration ||
         holdDuration != oldDelegate.holdDuration;
}

4. 额外优化建议

  • 确保在dispose方法中正确释放动画控制器:
    @override
    void dispose() {
      _controller.dispose();
      super.dispose();
    }
    
  • 如果_roundDuration、_moveDuration、_holdDuration是固定值,建议定义为常量,避免运行时重复计算。

内容的提问来源于stack exchange,提问作者Fever

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 22:00:57