返回

抛弃 setState,拥抱 Flutter 动画的新时代

Android

告别 setState,拥抱 Flutter 动画新时代

在 Flutter 的世界中,动画一直是一个必不可少的元素,它赋予了我们的应用程序生命力。然而,传统的 setState() 方法可能限制了我们的创造力,并带来了性能问题。现在是时候拥抱 Flutter 动画的新时代了,探索更有效的方法来管理和优化你的动画。

动画生命周期

让我们从了解动画生命周期开始。每当界面发生变化时,都会触发一帧更新。这一系列更新包括:

  • Animate: 计算动画值的变化。
  • Build: 基于动画值重新构建小部件树。
  • Layout: 确定小部件在屏幕上的位置和大小。
  • Compositing bits: 将小部件组合成位图。
  • Paint: 将位图绘制到屏幕上。
  • Compositing: 将位图与其他层合成。

当左侧 UI 时间过高时,表明你的界面存在问题。例如:

一帧触发 | UI 时间(左) | 光栅时间(右)
------- | -------- | ----------
1       | 16.67ms   | 16.67ms
2       | 16.67ms   | 16.67ms
...
4       | 66.67ms   | 16.67ms
5       | 16.67ms   | 16.67ms
...

在上面的示例中,当第四帧发生时,UI 时间突然飙升至 66.67ms,而光栅时间保持不变。这表明在第四帧中存在一些开销,导致 UI 渲染时间过长。

优化动画性能

要优化动画性能,我们需要关注以下关键点:

  • 使用 Animate(): Animate() 方法仅在动画值发生变化时触发,避免了不必要的重建。
  • 批处理更新: 使用 Future.wait() 或 SchedulerBinding.addPostFrameCallback() 批处理多个更新,减少重建次数。
  • 使用 AnimatedBuilder: AnimatedBuilder 小部件可以让你在动画值发生变化时仅重建受影响的部分,而不是整个小部件树。
  • 使用 AnimatedValue: AnimatedValue 提供了一个可观察的动画值,可以在其值发生变化时自动更新 UI。

案例研究:从 setState() 到 Animate()

让我们以一个实际示例来说明这些技术的好处。以下是如何使用 setState() 实现一个简单的动画:

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  double _progress = 0.0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        LinearProgressIndicator(value: _progress),
        ElevatedButton(
          onPressed: () {
            setState(() {
              _progress += 0.1;
            });
          },
          child: Text('Update'),
        ),
      ],
    );
  }
}

使用 Animate(),我们可以显著优化性能:

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  final ValueNotifier<double> _progress = ValueNotifier(0.0);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        LinearProgressIndicator(value: _progress.value),
        ElevatedButton(
          onPressed: () {
            _progress.value += 0.1;
          },
          child: Text('Update'),
        ),
      ],
    );
  }
}

通过使用 ValueNotifier,我们避免了不必要的重建,因为只有当 _progress.value 发生变化时才触发构建。

结论

告别 setState(),拥抱 Flutter 动画的新时代。通过利用 Animate()、Build、Layout 和其他优化技术,我们可以创建流畅、响应迅速且高效的动画。告别性能瓶颈,让你的应用程序在移动设备上尽情绽放。