数据绑定
数据绑定让你可以把 Rive 编辑器中设置为可绑定的元素连接到运行时代码。通过 View Model(视图模型)和 ViewModelInstance(视图模型实例),你可以读取、写入并监听属性变化,从而让 Flutter 应用中的状态与 Rive 动画保持同步。
数据绑定通常包含以下步骤:
- 从
.riv文件中获取ViewModel。 - 创建或获取一个
ViewModelInstance。 - 将
ViewModelInstance绑定到状态机或 Artboard。 - 读取、写入或监听绑定属性。
如果你使用 RiveWidgetController,很多绑定步骤会自动完成。
视图模型
ViewModel 是在 Rive 编辑器中定义的数据结构。它描述了一组可绑定属性,例如数字、字符串、布尔值、颜色、枚举、图片、列表、Artboard 等。
在 Flutter 运行时中,你可以从 File 获取视图模型:按名称获取、按索引获取,或获取某个 Artboard 的默认视图模型。
如果你正在使用 RiveWidgetController,可以跳过手动创建 ViewModel 的步骤,直接前往 视图模型实例。
// Get reference to the File and Artboard
final file = await File.asset(
'assets/my_file.riv',
riveFactory: Factory.rive,
);
final artboard = file!.defaultArtboard()!;
// Get reference by name
file.viewModelByName("My View Model");
// Get reference by index
for (var i = 0; i < file.viewModelCount; i++) {
final indexedVM = file.viewModelByIndex(i);
}
// Get reference to the default view model for an artboard
final defaultVM = file.defaultArtboardViewModel(artboard);
// Dispose the view model when you're no longer using it
viewModel.dispose();
视图模型实例
ViewModelInstance 是 ViewModel 的具体实例。你可以把它理解为视图模型的数据对象:ViewModel 定义有哪些属性,而 ViewModelInstance 持有这些属性的实际值。
一个 ViewModel 可以有多个实例。实例可以是空白实例,也可以来自 Rive 编辑器中导出的默认实例、命名实例或索引实例。
使用 RiveWidgetController
如果你使用 RiveWidgetController,可以通过 controller.dataBind(...) 直接创建并绑定视图模型实例。
// Get reference to the File
file = await File.asset(
'assets/rewards.riv',
riveFactory: Factory.rive,
);
// Create a controller
controller = RiveWidgetController(file!);
// Data bind by name
viewModelInstance = controller.dataBind(DataBind.byName('My View Model'));
// Data bind by index
viewModelInstance = controller.dataBind(DataBind.byIndex(0));
// Auto data bind
viewModelInstance = controller.dataBind(DataBind.auto());
// Bind some existing view model instance to the controller:
viewModelInstance = controller.dataBind(DataBind.byInstance(someViewModelInstance));
// Dispose of objects you created when no longer needed
viewModelInstance.dispose();
controller.dispose();
file.dispose();
手动管理视图模型实例
如果你想自己管理视图模型实例的创建,可以从 ViewModel 创建实例。
final vm = file.viewModelByName("My View Model")!;
// Create blank
final vmiBlank = vm.createInstance();
// Create default
final vmiDefault = vm.createDefaultInstance();
// Create by index
for (int i = 0; i < vm.instanceCount; i++) {
final vmiIndexed = vm.createInstanceByIndex(i);
}
// Create by name
final vmiNamed = vm.createInstanceByName("My Instance");
// Dispose the view model instance
viewModelInstance.dispose();
绑定
绑定是把 ViewModelInstance 连接到状态机或 Artboard 的过程。绑定后,Rive 文件中使用该视图模型的属性会与运行时代码中的实例数据联动。
如果你使用 RiveWidgetController,调用以下任意方法时会自动完成绑定:
viewModelInstance = controller.dataBind(DataBind.auto());
viewModelInstance = controller.dataBind(DataBind.byName('My View Model'));
viewModelInstance = controller.dataBind(DataBind.byIndex(0));
viewModelInstance = controller.dataBind(DataBind.byInstance(someViewModelInstance));
否则,你需要确保把视图模型实例绑定到状态机或 Artboard。
final file = await File.asset(
'assets/my_file.riv',
riveFactory: Factory.rive,
);
final artboard = file!.defaultArtboard();
final stateMachine = artboard!.defaultStateMachine()!;
final vm = file.defaultArtboardViewModel(artboard)!;
final vmi = vm.createDefaultInstance()!;
// Bind to the state machine. This automatically binds to the artboard as well.
stateMachine.bindViewModelInstance(vmi);
// If you're not using a state machine, bind to the artboard
artboard.bindViewModelInstance(vmi);
自动绑定
自动绑定会让运行时根据 Rive 文件中的默认设置选择合适的视图模型并创建实例。对于常见场景,这是最简单的方式。
// Get reference to the File
file = await File.asset(
'assets/rewards.riv',
riveFactory: Factory.rive,
);
// Create a controller
controller = RiveWidgetController(file!);
// Auto data bind
viewModelInstance = controller.dataBind(DataBind.auto());
// Dispose of objects you created when no longer needed
viewModelInstance.dispose();
controller.dispose();
file.dispose();
属性
视图模型由属性组成。属性可以是数字、字符串、布尔值、颜色、枚举、图片、列表、Artboard 或嵌套的视图模型等。
在运行时,你可以从 ViewModel 或 ViewModelInstance 查看可用属性,也可以从 ViewModelInstance 读取和写入具体属性值。
列出属性
可以在 ViewModel 对象或 ViewModelInstance 对象上访问 properties,以查看可用属性。
// Access on a ViewModel object
print("Properties: ${viewModel.properties}");
// Access on a ViewModelInstance object
print("Properties: ${viewModelInstance.properties}");
读取和写入属性
通过属性名称可以从 ViewModelInstance 获取属性对象。属性对象提供 value,可用于读取或设置当前值。
// Get reference to the ViewModel instance
final vmi = someExistingViewModelInstance;
final numberProperty = vmi.number("My Number Property")!;
// Get
final numberValue = numberProperty.value;
// Set
numberProperty.value = 10;
// Observe
void onNumberChange(double value) {
print("Number changed to: $value");
}
numberProperty.addListener(onNumberChange);
// Remove listener when done
numberProperty.removeListener(onNumberChange);
// Alternatively, clear all listeners
numberProperty.clearListeners();
// Dispose of the property to clear up resources when you're no longer using it
// This will call `clearListeners()` internally.
numberProperty.dispose();
嵌套属性路径
如果视图模型中包含嵌套视图模型,可以通过链式访问逐级获取属性,也可以使用以 / 分隔的路径直接访问嵌套属性。
// Get reference to the ViewModel instance
final vmi = someExistingViewModelInstance;
final nestedNumberByChain = vmi
.viewModel("My Nested View Model")!
.viewModel("My Second Nested VM")!
.number("My Nested Number");
final nestedNumberByPath = vmi.number("My Nested View Model/My Second Nested VM/My Nested Number");
可观察性
属性支持监听变化。你可以使用 addListener 注册回调,在属性值变化时收到通知;不再需要时使用 removeListener、clearListeners 或 dispose 清理监听器。
// Get reference to the ViewModel instance
final vmi = someExistingViewModelInstance;
final numberProperty = vmi.number("My Number Property")!;
// Get
final numberValue = numberProperty.value;
// Set
numberProperty.value = 10;
// Observe
void onNumberChange(double value) {
print("Number changed to: $value");
}
numberProperty.addListener(onNumberChange);
// Remove listener when done
numberProperty.removeListener(onNumberChange);
// Alternatively, clear all listeners
numberProperty.clearListeners();
// Dispose of the property to clear up resources when you're no longer using it
// This will call `clearListeners()` internally.
numberProperty.dispose();
图片
图片属性允许你在运行时把图片数据设置到 Rive 文件中的绑定图片属性上。
通常流程是:
- 从
ViewModelInstance获取图片属性。 - 使用
Factory.rive.decodeImage(bytes)或Factory.flutter.decodeImage(bytes)解码图片。 - 将得到的
RenderImage设置为图片属性的value。
请参阅 Flutter 数据绑定图片示例:databinding_images.dart。
// Access the image property by path on a ViewModelInstance object
final imageProperty = viewModelInstance.image('my_image')!; // image property named "my_image"
// Create a RenderImage
final renderImage = await Factory.rive.decodeImage(bytes); // use `Factory.flutter` if you're using the Flutter renderer
// If the image is valid, update the image property value
if (renderImage != null) {
imageProperty.value = renderImage;
}
// You can also set the image property to null to clear it
imageProperty.value = null;
列表
Flutter 中的列表 API 设计为与 Dart 的 List 类相似。它没有包含 List 的完整 API,但提供了最常用的方法。
使用列表时,如果访问越界索引,或执行不允许的列表操作,可能会抛出错误(RangeError)。这与 Dart 的 List API 类似。
在 ViewModelInstance 对象上通过路径访问列表属性:
final todosProperty = viewModelInstance.list('todos')!; // list property named "todos"
print(todosProperty.length); // print the length of the list
要添加一个条目,需要先创建要添加到列表中的视图模型实例:
final todoItemVM = riveFile.viewModelByName("TodoItem")!;
final todoItemInstance = todoItemVM.createInstance()!;
你也可以使用从 Rive 编辑器导出的现有实例来创建实例:
createDefaultInstance()createInstanceByName('exercise')createInstanceByIndex(0)
然后把实例添加到列表中:
todosProperty.add(todoItemInstance);
要从列表中移除某个特定实例,可以使用 remove 方法:
todosProperty.remove(todoItemInstance);
其他操作:
// Remove at index
todosProperty.removeAt(0); // can throw
// Insert at index
todosProperty.insert(0, todoItemInstance); // can throw
// Swap
todosProperty.swap(0, 1); // can throw
// First
ViewModelInstance todo = todosProperty.first(); // can throw
// Last
ViewModelInstance todo = todosProperty.last(); // can throw
// First or null
ViewModelInstance? todo = todosProperty.firstOrNull(); // will return null if the list is empty
// Last or null
ViewModelInstance? todo = todosProperty.lastOrNull(); // will return null if the list is empty
// Access/set directly by index
final instance = todosProperty[0]; // can throw
todosProperty[0] = todoItemInstance; // can throw
// Instance at index
todosProperty.instanceAt(2); // can throw
// Length
todosProperty.length;
Artboard
Artboard 属性使用 BindableArtboard 类,它不同于包中的常规 Artboard 类。
BindableArtboard 是一个运行时包装器,用于通过数据绑定与 Artboard 交互。这些实例引用文件中已有的 Artboard,因此不需要在 Rive 编辑器中进行额外设置。
请参阅 Flutter 数据绑定 Artboard 示例:databinding_artboards.dart。
// Artboard property to bind
final artboardProp = viewModelInstance.artboard('artboardPropertyName')!;
// Create a bindable artboard
final bindableArtboard = riveFile.artboardToBind('artboardName')!;
artboardProp.value = bindableArtboard;
枚举
如果 Rive 文件中定义了数据枚举,可以通过 File 对象访问它们。
// Access on a File object
print("Data enums: ${file.enums}");
示例
- 数据绑定概览:
databinding.dart - 数据绑定图片:
databinding_images.dart - 数据绑定 Artboard:
databinding_artboards.dart - 数据绑定列表:
databinding_lists.dart