Flutter动画框架插件keframe的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter 动画框架插件 Keframe 的使用

概述

Keframe 是一个用于优化Flutter应用流畅度的组件,通过分帧渲染技术来解决构建过程中可能引起的卡顿问题,如页面切换或复杂列表的快速滚动。它能够显著提高应用性能,减少掉帧现象,使用户界面更加流畅。

image

优化前后对比

Before optimization After optimization
优化前 优化后

从上面的数据可以看出,在相同的操作下(200帧),使用分帧优化后,卡顿次数从平均33.3次降低到了仅一次,轻微卡顿时间也从188ms减少到90ms,整体表现更为流畅。

使用方法

项目依赖配置

pubspec.yaml文件中添加对keframe的依赖:

dependencies:
  keframe: ^2.0.6 # null-safe 版本

快速入门

假设页面由四个部分A、B、C和D组成,每个部分需要10ms来构建,总共需要40ms。我们可以通过嵌套FrameSeparateWidget组件来分别处理每一部分,这样在页面首次加载时会先显示简单的占位符,然后逐帧渲染各个子项。

对于列表,可以在每个item中嵌套FrameSeparateWidget,并在外部包裹一层SizeCacheWidget以缓存尺寸信息,从而提升快速滚动时的响应速度。

SizeCacheWidget(
  child: ListView.builder(
    cacheExtent: 500, // 增大预加载区域
    itemCount: childCount,
    itemBuilder: (context, index) => FrameSeparateWidget(
      index: index,
      placeHolder: Container(
        color: index % 2 == 0 ? Colors.red : Colors.blue,
        height: 60,
      ),
      child: CellWidget(
        color: index % 2 == 0 ? Colors.red : Colors.blue,
        index: index,
      ),
    ),
  ),
)

构造函数说明

FrameSeparateWidget

这是一个分帧渲染组件,允许将嵌套的小部件在一个单独的帧内进行渲染。

  • index: 分帧组件ID,在SizeCacheWidget场景下传递,并维护与SizeCacheWidget对应的尺寸信息。
  • child: 需要实际渲染的小部件。
  • placeHolder: 占位符小部件,默认为Container(),建议设置简单且类似实际项目的占位图。

SizeCacheWidget

用于缓存分帧组件子节点中的实际小部件大小。

  • estimateCount: 预估屏幕上能显示的子节点数量,可加快快速滚动场景下的响应速度。
  • child: 如果包含分帧组件,则缓存的是实际小部件的尺寸。

示例代码

下面是一个完整的示例demo,展示了如何利用Keframe优化ListView:

import 'package:flutter/material.dart';
import 'package:keframe/keframe.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Keframe Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Keframe Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Expanded(
              child: SizeCacheWidget(
                estimateCount: 20,
                child: ListView.builder(
                  cacheExtent: 500,
                  itemCount: 100,
                  itemBuilder: (context, index) {
                    return FrameSeparateWidget(
                      index: index,
                      placeHolder: Container(
                        color: index % 2 == 0 ? Colors.red : Colors.blue,
                        height: 60,
                      ),
                      child: ListTile(
                        title: Text('Item $index'),
                        subtitle: Text('This is item number $index'),
                      ),
                    );
                  },
                ),
              ),
            ),
            ElevatedButton(
              onPressed: _incrementCounter,
              child: Text('Increment Counter ($_counter)'),
            ),
          ],
        ),
      ),
    );
  }
}

这个例子创建了一个带有计数器按钮的应用程序,并且有一个经过Keframe优化过的ListView。当用户点击按钮时,计数器会增加;同时,ListView中的每一项都会被逐帧渲染出来,从而减少了初次渲染的时间并提高了用户体验。

如果您有任何问题或建议,请随时联系开发者团队!如果这篇文章对您有所启发,请不要忘记给项目点个Star哦!✨✨✨✨


希望这段内容能够帮助您更好地理解和使用Keframe插件。如果有更多关于Flutter的问题,欢迎继续提问!


更多关于Flutter动画框架插件keframe的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter动画框架插件keframe的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,keyframe_animation 插件允许你创建复杂的动画,通过定义关键帧(keyframes)来控制动画的每一个阶段。虽然 Flutter 本身已经提供了丰富的动画支持,但 keyframe_animation 插件进一步增强了动画的能力,使得开发者能够更精细地控制动画过程。

以下是一个使用 keyframe_animation 插件的简单示例,展示了如何创建一个沿路径移动的动画对象。

首先,确保你已经在 pubspec.yaml 文件中添加了 keyframe_animation 依赖:

dependencies:
  flutter:
    sdk: flutter
  keyframe_animation: ^x.y.z  # 请替换为最新版本号

然后,运行 flutter pub get 来获取依赖。

接下来,是一个完整的 Flutter 应用示例,展示如何使用 keyframe_animation

import 'package:flutter/material.dart';
import 'package:keyframe_animation/keyframe_animation.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Keyframe Animation Example'),
        ),
        body: AnimationExample(),
      ),
    );
  }
}

class AnimationExample extends StatefulWidget {
  @override
  _AnimationExampleState createState() => _AnimationExampleState();
}

class _AnimationExampleState extends State<AnimationExample> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<Offset> _animation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..repeat(reverse: true);

    // 定义关键帧动画
    final List<Keyframe<Offset>> keyframes = [
      Keyframe<Offset>(
        fraction: 0.0,
        value: Offset.zero,
      ),
      Keyframe<Offset>(
        fraction: 0.5,
        value: const Offset(0.5, 0.5),
      ),
      Keyframe<Offset>(
        fraction: 1.0,
        value: const Offset(1.0, 0.0),
      ),
    ];

    // 使用关键帧生成动画
    final TweenSequence<Offset> tweenSequence = TweenSequence<Offset>(keyframes);
    _animation = tweenSequence.animate(_controller);
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: Alignment.center,
      children: [
        Positioned(
          left: _animation.value.dx * 300, // 假设屏幕宽度为300
          top: _animation.value.dy * 300,  // 假设屏幕高度为300
          child: Container(
            width: 50,
            height: 50,
            color: Colors.blue,
          ),
        ),
      ],
    );
  }
}

在这个示例中:

  1. 我们创建了一个 AnimationController 来控制动画的时长和循环。
  2. 定义了一组 Keyframe<Offset>,每个关键帧指定了在动画某个阶段(由 fraction 表示)的位置(Offset)。
  3. 使用 TweenSequence<Offset> 将这些关键帧组合成一个动画序列。
  4. 通过 _controller 控制这个动画序列,并将其值应用到一个小容器的位置上,使容器在屏幕上沿指定路径移动。

这个示例展示了 keyframe_animation 插件的基本用法,你可以根据需要添加更多关键帧、调整动画属性或组合不同的动画效果来创建复杂的动画。

回到顶部