mirror of
https://github.com/rive-app/rive-flutter.git
synced 2025-06-28 02:37:16 +08:00
Adds onStateChange callback
This commit is contained in:
@ -1,8 +1,13 @@
|
||||
## [0.7.21] - 2021-06-21 14:00:00
|
||||
- Adds onStateChange callback to state machine controllers
|
||||
|
||||
## [0.7.20] - 2021-06-19 19:01:10
|
||||
- Quick start fixes in README.md.
|
||||
- Quick start fixes in README.md
|
||||
|
||||
## [0.7.19] - 2021-06-18 12:00:00
|
||||
- BREAKING CHANGE: onInit callback now takes an artboard as a parameter
|
||||
- Adds simple state machine example
|
||||
|
||||
## [0.7.18] - 2021-06-14 12:00:00
|
||||
- Adds ability to pass controllers into RiveAnimation widgets
|
||||
- Adds autoplay option to SimpleAnimation controller
|
||||
|
@ -8,7 +8,7 @@ Runtime docs are available in [Rive's help center](https://help.rive.app/runtime
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
rive: ^0.7.20
|
||||
rive: ^0.7.21
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
@ -15,6 +15,9 @@ class _LittleMachineState extends State<LittleMachine> {
|
||||
/// Tracks if the animation is playing by whether controller is running.
|
||||
bool get isPlaying => _controller?.isActive ?? false;
|
||||
|
||||
/// Message that displays when state has changed
|
||||
String stateChangeMessage = '';
|
||||
|
||||
Artboard? _riveArtboard;
|
||||
StateMachineController? _controller;
|
||||
SMIInput<bool>? _trigger;
|
||||
@ -33,8 +36,11 @@ class _LittleMachineState extends State<LittleMachine> {
|
||||
// The artboard is the root of the animation and gets drawn in the
|
||||
// Rive widget.
|
||||
final artboard = file.mainArtboard;
|
||||
var controller =
|
||||
StateMachineController.fromArtboard(artboard, 'State Machine 1');
|
||||
var controller = StateMachineController.fromArtboard(
|
||||
artboard,
|
||||
'State Machine 1',
|
||||
onStateChange: _onStateChange,
|
||||
);
|
||||
if (controller != null) {
|
||||
artboard.addController(controller);
|
||||
_trigger = controller.findInput('Trigger 1');
|
||||
@ -44,6 +50,12 @@ class _LittleMachineState extends State<LittleMachine> {
|
||||
);
|
||||
}
|
||||
|
||||
/// Do something when the state machine changes state
|
||||
void _onStateChange(String stateMachineName, String stateName) => setState(
|
||||
() => stateChangeMessage =
|
||||
'State Changed in $stateMachineName to $stateName',
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -71,6 +83,9 @@ class _LittleMachineState extends State<LittleMachine> {
|
||||
artboard: _riveArtboard!,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text('$stateChangeMessage'),
|
||||
const SizedBox(height: 10),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -119,7 +119,10 @@ class StateMachineController extends core.StateMachineController {
|
||||
/// A list of inputs available in the StateMachine.
|
||||
Iterable<SMIInput> get inputs => _inputs;
|
||||
|
||||
StateMachineController(StateMachine stateMachine) : super(stateMachine) {
|
||||
StateMachineController(
|
||||
StateMachine stateMachine, {
|
||||
core.OnStateChange? onStateChange,
|
||||
}) : super(stateMachine, onStateChange: onStateChange) {
|
||||
isActive = true;
|
||||
for (final input in stateMachine.inputs) {
|
||||
switch (input.coreType) {
|
||||
@ -140,10 +143,13 @@ class StateMachineController extends core.StateMachineController {
|
||||
/// [stateMachineName]. Returns the [StateMachineController] or null if no
|
||||
/// [StateMachine] with [stateMachineName] is found.
|
||||
static StateMachineController? fromArtboard(
|
||||
Artboard artboard, String stateMachineName) {
|
||||
Artboard artboard,
|
||||
String stateMachineName, {
|
||||
core.OnStateChange? onStateChange,
|
||||
}) {
|
||||
for (final animation in artboard.animations) {
|
||||
if (animation is StateMachine && animation.name == stateMachineName) {
|
||||
return StateMachineController(animation);
|
||||
return StateMachineController(animation, onStateChange: onStateChange);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:rive/src/core/core.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:rive/src/rive_core/animation/animation_state_instance.dart';
|
||||
@ -12,6 +13,16 @@ import 'package:rive/src/rive_core/animation/state_machine_layer.dart';
|
||||
import 'package:rive/src/rive_core/animation/state_transition.dart';
|
||||
import 'package:rive/src/rive_core/rive_animation_controller.dart';
|
||||
|
||||
import 'animation/animation_state.dart';
|
||||
import 'animation/entry_state.dart';
|
||||
import 'animation/exit_state.dart';
|
||||
|
||||
/// Callback signature for satate machine state changes
|
||||
typedef OnStateChange = void Function(String, String);
|
||||
|
||||
/// Callback signature for layer state changes
|
||||
typedef OnLayerStateChange = void Function(LayerState);
|
||||
|
||||
class LayerController {
|
||||
final StateMachineLayer layer;
|
||||
final StateInstance anyStateInstance;
|
||||
@ -23,7 +34,11 @@ class LayerController {
|
||||
double _mix = 1.0;
|
||||
double _mixFrom = 1.0;
|
||||
|
||||
LayerController(this.layer)
|
||||
/// Optional callback which is called when a state changes
|
||||
/// Takes the state machine name and state name
|
||||
final OnLayerStateChange? onLayerStateChange;
|
||||
|
||||
LayerController(this.layer, {this.onLayerStateChange})
|
||||
: assert(layer.anyState != null),
|
||||
anyStateInstance = layer.anyState!.makeInstance() {
|
||||
_changeState(layer.entryState);
|
||||
@ -167,6 +182,10 @@ class LayerController {
|
||||
// Make sure to reset _waitingForExit to false if we succeed at taking a
|
||||
// transition.
|
||||
_waitingForExit = false;
|
||||
// State has changed, fire the callback if there's one
|
||||
if (_currentState != null) {
|
||||
onLayerStateChange?.call(_currentState!.state);
|
||||
}
|
||||
return true;
|
||||
} else if (allowed == AllowTransition.waitingForExit) {
|
||||
_waitingForExit = true;
|
||||
@ -179,9 +198,14 @@ class LayerController {
|
||||
class StateMachineController extends RiveAnimationController<CoreContext> {
|
||||
final StateMachine stateMachine;
|
||||
final inputValues = HashMap<int, dynamic>();
|
||||
StateMachineController(this.stateMachine);
|
||||
final layerControllers = <LayerController>[];
|
||||
|
||||
/// Optional callback for state changes
|
||||
final OnStateChange? onStateChange;
|
||||
|
||||
/// Constructor that takes a state machine and optional state change callback
|
||||
StateMachineController(this.stateMachine, {this.onStateChange});
|
||||
|
||||
void _clearLayerControllers() {
|
||||
for (final layer in layerControllers) {
|
||||
layer.dispose();
|
||||
@ -189,12 +213,33 @@ class StateMachineController extends RiveAnimationController<CoreContext> {
|
||||
layerControllers.clear();
|
||||
}
|
||||
|
||||
/// Handles state change callbacks
|
||||
void _onStateChange(LayerState layerState) =>
|
||||
SchedulerBinding.instance?.addPostFrameCallback((_) {
|
||||
String stateName = 'unknown';
|
||||
print('Layer state type ${layerState.runtimeType}');
|
||||
if (layerState is AnimationState && layerState.animation != null) {
|
||||
stateName = layerState.animation!.name;
|
||||
} else if (layerState is EntryState) {
|
||||
stateName = 'EntryState';
|
||||
} else if (layerState is AnyState) {
|
||||
stateName = 'EntryState';
|
||||
} else if (layerState is ExitState) {
|
||||
stateName = 'ExitState';
|
||||
}
|
||||
|
||||
onStateChange?.call(stateMachine.name, stateName);
|
||||
});
|
||||
|
||||
@override
|
||||
bool init(CoreContext core) {
|
||||
_clearLayerControllers();
|
||||
|
||||
for (final layer in stateMachine.layers) {
|
||||
layerControllers.add(LayerController(layer));
|
||||
layerControllers.add(LayerController(
|
||||
layer,
|
||||
onLayerStateChange: _onStateChange,
|
||||
));
|
||||
}
|
||||
|
||||
// Make sure triggers are all reset.
|
||||
|
Reference in New Issue
Block a user