Flutter动画渲染插件rive_native的使用
Flutter动画渲染插件rive_native的使用
Rive Native 是一个新的运行时,它允许你在 Flutter 应用中显示和交互 Rive 图形。Rive Native 由 Rive 渲染器(Rive Renderer)驱动,通过 FFI(Foreign Function Interface)与 Rive 的 C++ 运行时进行交互。
Rive Native 与当前 Rive Flutter 运行时的区别
- rive_native 使用 Rive 的 C++ 运行时通过 FFI 驱动,不再通过 Dart 实现的相同运行时。这确保了跨平台的一致性体验,并且能够在未来实现性能改进和新功能,如响应式布局。
- rive_native 将 Rive 渲染器引入到 Flutter 中。你仍然可以选择使用基于 Flutter 的渲染器(Dart / Impeller)。在某些情况下,一个比另一个更受欢迎。我们将提供更多文档来帮助你根据具体需求选择正确的渲染器。如果性能是首要考虑因素,我们建议使用 Rive 渲染器。未来,高度请求的功能(如辉光和阴影)可能仅由 Rive 渲染器支持。
技术预览
该软件包目前处于技术预览阶段,并不支持所有来自当前 Rive Flutter 运行时的功能和平台。
我们正在努力添加对所有主要功能的支持。
平台支持
平台 | Flutter 渲染器 | Rive 渲染器 |
---|---|---|
iOS | ✅ | ✅ |
Android | ❌ | ❌ |
macOS | ✅ | ✅ |
Windows | ✅ | ✅ |
Linux | ❌ | ❌ |
Web | ✅ | ✅ |
注意:iOS 模拟器支持当前不可用。请使用真实设备进行测试。
功能支持
功能 | 支持情况 |
---|---|
设置状态机输入 | ✅ |
设置状态机嵌套输入 | ❌ |
更新文本运行 | ✅ |
更新嵌套文本运行 | ❌ |
响应式布局 | ✅ |
Rive 音频 | ✅ |
离线资源 | ❌ |
Rive 事件 | ❌ |
入门指南
rive_native
目前还没有在 GitHub 上公开发布,但很快就会发布。现在你可以通过以下步骤拉取源代码和示例:
dart pub unpack rive_native
cd rive_native/example
flutter pub get
flutter run
正在开发一个更高层次的声明性 API,以使在 Flutter 应用中使用 Rive 图形更加容易。
请参阅 rive_native/example/rive_player.dart
文件中的示例实现,了解如何使用此包。
排错
相关的本地库应该会在构建步骤(flutter run
或 flutter build
)期间自动下载。
如果你遇到问题,请尝试以下操作:
flutter clean
flutter pub get
flutter run
或者,你也可以直接运行 rive_native
设置脚本。在你的 Flutter 应用根目录下运行:
dart run rive_native:setup --verbose --clean --platform macos
这将清理 rive_native
设置并下载指定平台的库,具体平台支持请参见上面的表格。
构建
默认情况下,预构建的本地库会被下载并使用。你也可以选择自己构建库,使用 rive_native
设置,传递 --build
标志:
flutter clean # 重要
dart run rive_native:setup --verbose --clean --build --platform macos
这将需要一些工具在你的机器上可用。我们很快会提供更多文档。
测试
共享库也包括在下载/构建过程中。如果你在测试中遇到使用 rive_native
的困难,请联系我们。
示例代码
以下是示例代码,展示了如何在 Flutter 应用中使用 rive_native
。
lib/main.dart
import 'package:flutter/material.dart';
import 'package:rive_native/rive_native.dart' as rive;
import 'examples/examples.dart';
import 'rive_player.dart';
const _appBarColor = Color(0xFF323232);
const _backgroundColor = Color(0xFF1D1D1D);
const _primaryColor = Color(0xFF57A5E0);
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await rive.RiveNative.init(); // 初始化 Rive Native
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
darkTheme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: _backgroundColor,
appBarTheme: const AppBarTheme(backgroundColor: _appBarColor),
colorScheme: ColorScheme.fromSwatch().copyWith(primary: _primaryColor),
),
themeMode: ThemeMode.dark,
home: const HomePage(),
);
}
}
class Demo {
final Widget widget;
final String text;
Demo(this.widget, this.text);
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
[@override](/user/override)
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<Demo> widgets = [
Demo(const ExampleBasic(), "Basic"),
Demo(const ExampleTickerMode(), "Ticker Mode"),
Demo(const ExampleResponsiveLayout(), "Responsive Layout"),
Demo(const ExampleTimeDilation(), "Time Dilation"),
Demo(const ExampleHitTestBehaviour(), "Hit test behaviour"),
Demo(const ExampleArtboardDoesNotExists(), "Artboard does not exists"),
];
bool isRiveRender = true; // 控制渲染器的选择
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Rive Native Examples"),
),
body: Column(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.only(top: 120),
child: ListView.builder(
itemCount: widgets.length,
itemBuilder: (context, index) {
return _button(widgets[index].text, () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return BasePage(child: widgets[index].widget);
},
),
);
});
},
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: isRiveRender
? const Text("Active Renderer: Rive")
: const Text("Active Renderer: Flutter (Skia or Impeller)")),
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
setState(() {
isRiveRender = true;
});
},
child: const Text("Rive Renderer"),
),
ElevatedButton(
onPressed: () {
setState(() {
isRiveRender = false;
});
},
child: const Text("Flutter Renderer"),
),
],
),
),
],
),
);
}
Widget _button(String title, VoidCallback onPressed) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Center(child: ElevatedButton(onPressed: onPressed, child: Text(title)))
);
}
}
class BasePage extends StatelessWidget {
const BasePage({super.key, required this.child});
final Widget child;
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Center(child: child),
),
);
}
}
更多关于Flutter动画渲染插件rive_native的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter动画渲染插件rive_native的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用rive_native
插件来实现动画渲染的示例代码。rive_native
插件允许你使用Rive动画文件(.riv)在你的Flutter应用中创建丰富、高质量的动画。
首先,确保你已经在你的pubspec.yaml
文件中添加了rive_native
依赖:
dependencies:
flutter:
sdk: flutter
rive_native: ^0.x.x # 请替换为最新版本号
然后,运行flutter pub get
来安装依赖。
接下来,你需要一个Rive动画文件(.riv)。假设你已经有一个名为animation.riv
的文件,你可以将其放置在assets
文件夹中,并在pubspec.yaml
中声明它:
flutter:
assets:
- assets/animation.riv
现在,你可以在你的Flutter应用中加载并使用这个Rive动画。以下是一个完整的示例代码:
import 'package:flutter/material.dart';
import 'package:rive/rive.dart';
import 'package:rive_native/rive_native.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Rive Animation Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Rive Animation Example'),
),
body: Center(
child: RiveAnimationWidget(),
),
),
);
}
}
class RiveAnimationWidget extends StatefulWidget {
@override
_RiveAnimationWidgetState createState() => _RiveAnimationWidgetState();
}
class _RiveAnimationWidgetState extends State<RiveAnimationWidget> {
late RiveAnimationController _controller;
late Artboard _artboard;
@override
void initState() {
super.initState();
loadAnimation();
}
void loadAnimation() async {
// 加载Rive文件
final riveFile = await RiveFile.asset('assets/animation.riv');
// 获取Artboard
_artboard = riveFile.mainArtboard!;
// 创建控制器并添加监听器以更新动画状态
_controller = RiveAnimationController.fromArtboard(
_artboard,
animations: ['idle'], // 这里指定你想播放的动画名称
);
// 开始动画
_controller.isActive = true;
// 设置状态以触发UI更新
setState(() {});
}
@override
Widget build(BuildContext context) {
// 在RiveAnimation组件中使用Artboard和控制器
return _controller.isMounted
? Rive(
artboard: _artboard,
animations: _controller.animations,
)
: Container(); // 在动画加载完成前显示空容器
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
在这个示例中,我们做了以下几件事:
- 在
pubspec.yaml
中添加了rive_native
依赖,并声明了Rive动画文件作为资产。 - 创建了一个Flutter应用,其中包含一个
RiveAnimationWidget
,用于显示Rive动画。 - 在
RiveAnimationWidget
的initState
方法中,异步加载Rive文件,获取主Artboard,并创建一个RiveAnimationController
来控制动画。 - 在
build
方法中,使用Rive
组件来显示动画,如果动画尚未加载完成,则显示一个空容器。 - 在
dispose
方法中,释放RiveAnimationController
以避免内存泄漏。
请注意,你需要根据你的具体Rive动画文件调整动画名称和其他参数。此外,rive_native
插件的API可能会随着版本的更新而变化,因此请参考最新的官方文档以获取最新信息。