feat: adds play and pause to artboard

An oversight from our side. We've previously recommended setting `isActive` to false on the StateMachine or Animation. But this will not propagate down to nested artboards.

Diffs=
e64daefff feat: adds play and pause to artboard (#7078)
2828b7b01 propagate volume to nested artboards (#7067)
4a9947630 Stop audio in iOS when backgrounded. (#7055)

Co-authored-by: Gordon <pggordonhayes@gmail.com>
This commit is contained in:
HayesGordon
2024-04-19 09:34:59 +00:00
parent a22fc5f047
commit e34fc4cc41
7 changed files with 66 additions and 16 deletions

View File

@ -1 +1 @@
024f95b100f1e76940c4dad707e54bb4f48e86d4
e64daefffdcd34df6a6cc9f5b54ebc92e0ae89cb

View File

@ -2,6 +2,7 @@
- Support for asset audio volume.
- Fixed an issue with audio decoder in web build.
- Adds `play()`/`pause()` and `isPlaying` to an `Artboard`. This completely stops the artboard from playing (including nested artboards) and stops/starts the animation ticker. Pausing an artboard can be used to reduce resources used for Rive graphics that aren't visible on screen.
## 0.13.1

View File

@ -11,20 +11,21 @@ class PlayPauseAnimation extends StatefulWidget {
}
class _PlayPauseAnimationState extends State<PlayPauseAnimation> {
/// Controller for playback
late RiveAnimationController _controller;
Artboard? _artboard;
/// Toggles between play and pause animation states
void _togglePlay() =>
setState(() => _controller.isActive = !_controller.isActive);
bool get isPlaying => _artboard?.isPlaying ?? true;
/// Tracks if the animation is playing by whether controller is running
bool get isPlaying => _controller.isActive;
/// Toggles between play and pause on the artboard
void _togglePlay() {
if (isPlaying) {
_artboard?.pause();
} else {
_artboard?.play();
}
@override
void initState() {
super.initState();
_controller = SimpleAnimation('idle');
// We call set state to update the Play/Pause Icon. This isn't needed
// to update Rive.
setState(() {});
}
@override
@ -35,10 +36,11 @@ class _PlayPauseAnimationState extends State<PlayPauseAnimation> {
),
body: RiveAnimation.asset(
'assets/off_road_car.riv',
animations: const ["idle"],
fit: BoxFit.cover,
controllers: [_controller],
// Update the play state when the widget's initialized
onInit: (_) => setState(() {}),
onInit: (artboard) {
_artboard = artboard;
},
),
floatingActionButton: FloatingActionButton(
onPressed: _togglePlay,

View File

@ -333,7 +333,7 @@ class RiveRenderObject extends RiveRenderBox implements MouseTrackerAnnotation {
@override
bool advance(double elapsedSeconds) =>
_artboard.advance(elapsedSeconds, nested: true);
_artboard.isPlaying && _artboard.advance(elapsedSeconds, nested: true);
@override
void beforeDraw(Canvas canvas, Offset offset) {

View File

@ -1,5 +1,6 @@
import 'dart:ui';
import 'package:meta/meta.dart';
import 'package:rive/src/core/core.dart';
import 'package:rive/src/generated/artboard_base.dart';
import 'package:rive/src/rive_core/animation/animation.dart';
@ -534,6 +535,26 @@ class Artboard extends ArtboardBase with ShapePaintContainer {
@override
void onStrokesChanged() {}
/// Sets `isPlaying` to true. Animations and state machines will play.
///
/// See [pause], to pause the artboard from advancing/drawing.
@mustBeOverridden
void play() {}
/// Sets `isPlaying` to false. Animations and state machines will not play.
/// This can be used to reduce resources when the animation is not visible
/// in the app.
///
/// See [play], to play the artboard and continue advancing/drawing.
@mustBeOverridden
void pause() {}
/// Indicates if the runtime artboard is active/playing. When `false` no
/// artboard animation or state machine will advance. The underlying animation
/// ticker is paused.
@mustBeOverridden
bool get isPlaying => true;
@override
Vec2D get worldTranslation => Vec2D();

View File

@ -29,6 +29,9 @@ class RuntimeArtboard extends Artboard implements CoreContext {
Iterable<Core?> get objects => _objects;
final Set<Component> _needDependenciesBuilt = {};
// Indicates if this artboard is playing or paused
bool _isPlaying = true;
@override
T? addObject<T extends Core>(T? object) {
object?.context = this;
@ -168,4 +171,18 @@ class RuntimeArtboard extends Artboard implements CoreContext {
.addPostFrameCallback((_) => controller.isActive = true);
}
}
@override
void pause() {
_isPlaying = false;
}
@override
void play() {
_isPlaying = true;
markNeedsAdvance();
}
@override
bool get isPlaying => _isPlaying;
}

View File

@ -39,4 +39,13 @@ void main() {
expect(artboard.linearAnimations.toList().length, 2);
expect(artboard.stateMachines.toList().length, 1);
});
test('Pausing/Playing an artboard', () {
final artboard = riveFile.mainArtboard.instance();
expect(artboard.isPlaying, true, reason: "Should be true by default");
artboard.pause();
expect(artboard.isPlaying, false, reason: "Should be false after pause");
artboard.play();
expect(artboard.isPlaying, true, reason: "Should be true after play");
});
}