diff --git a/CHANGELOG.md b/CHANGELOG.md index ad79a15..611711b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [0.7.18] - 2021-06-14 12:00:00 +- Adds ability to pass controllers into RiveAnimation widgets +- Adds autoplay option to SimpleAnimation controller + ## [0.7.17] - 2021-06-11 18:00:00 - Exposes antialiasing option in Rive and RiveAnimation widgets. diff --git a/README.md b/README.md index 3970b20..a9d7db0 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Runtime docs are available in [Rive's help center](https://help.rive.app/runtime ```yaml dependencies: - rive: ^0.7.17 + rive: ^0.7.18 ``` ## Quick Start diff --git a/example/lib/play_pause_animation.dart b/example/lib/play_pause_animation.dart index 64ff1b8..fbc2f28 100644 --- a/example/lib/play_pause_animation.dart +++ b/example/lib/play_pause_animation.dart @@ -12,12 +12,11 @@ class _PlayPauseAnimationState extends State { // Controller for playback late RiveAnimationController _controller; - // This will toggle between play and pause states for the animation - void _togglePlay() { - setState(() => _controller.isActive = !_controller.isActive); - } + // Toggles between play and pause animation states + void _togglePlay() => + setState(() => _controller.isActive = !_controller.isActive); - /// Tracks if the animation is playing by whether controller is running. + /// Tracks if the animation is playing by whether controller is running bool get isPlaying => _controller.isActive; @override @@ -33,9 +32,11 @@ class _PlayPauseAnimationState extends State { title: const Text('Animation Example'), ), body: Center( - child: RiveControllerAnimation.network( + child: RiveAnimation.network( 'https://cdn.rive.app/animations/vehicles.riv', controllers: [_controller], + // Update the play state when the widget's initialized + onInit: () => setState(() {}), ), ), floatingActionButton: FloatingActionButton( diff --git a/lib/src/controllers/simple_controller.dart b/lib/src/controllers/simple_controller.dart index 784e534..d38a3f5 100644 --- a/lib/src/controllers/simple_controller.dart +++ b/lib/src/controllers/simple_controller.dart @@ -17,12 +17,21 @@ import 'package:rive/src/runtime_artboard.dart'; class SimpleAnimation extends RiveAnimationController { LinearAnimationInstance? _instance; + /// Animation name final String animationName; + + /// Stops the animation on the next apply + /// bool _stopOnNextApply = false; + + /// Pauses the animation when it's created + final bool autoplay; + + /// Mix value for the animation, value between 0 and 1 double _mix; // Controls the level of mix for the animation, clamped between 0 and 1 - SimpleAnimation(this.animationName, {double mix = 1}) + SimpleAnimation(this.animationName, {double mix = 1, this.autoplay = true}) : _mix = mix.clamp(0, 1).toDouble(); LinearAnimationInstance? get instance => _instance; double get mix => _mix; @@ -51,7 +60,7 @@ class SimpleAnimation extends RiveAnimationController { @override bool init(RuntimeArtboard artboard) { _instance = artboard.animationByName(animationName); - isActive = true; + isActive = autoplay; return _instance != null; } diff --git a/lib/src/widgets/rive_animation.dart b/lib/src/widgets/rive_animation.dart index 8dc557a..03853da 100644 --- a/lib/src/widgets/rive_animation.dart +++ b/lib/src/widgets/rive_animation.dart @@ -1,7 +1,10 @@ +import 'dart:ui' show VoidCallback; + import 'package:flutter/widgets.dart'; import 'package:rive/rive.dart'; import 'package:rive/src/rive_core/artboard.dart'; +/// Specifies whether a source is from an asset bundle or http enum _Source { asset, network, @@ -32,11 +35,18 @@ class RiveAnimation extends StatefulWidget { /// Alignment for the animation in the widget final Alignment? alignment; + /// Widget displayed while the rive is loading + final Widget? placeHolder; + /// Enable/disable antialiasing when rendering final bool antialiasing; - /// Widget displayed while the rive is loading - final Widget? placeHolder; + /// Controllers for instanced animations and state machines; use this + /// to directly control animation states instead of passing names. + final List controllers; + + /// Callback fired when Riveanimation has initialized + final VoidCallback? onInit; /// Creates a new RiveAnimation from an asset bundle const RiveAnimation.asset( @@ -48,6 +58,8 @@ class RiveAnimation extends StatefulWidget { this.alignment, this.placeHolder, this.antialiasing = true, + this.controllers = const [], + this.onInit, }) : src = _Source.asset; const RiveAnimation.network( @@ -59,6 +71,8 @@ class RiveAnimation extends StatefulWidget { this.alignment, this.placeHolder, this.antialiasing = true, + this.controllers = const [], + this.onInit, }) : src = _Source.network; @override @@ -83,7 +97,7 @@ class _RiveAnimationState extends State { } } - /// Initializes the artboard, animation, and controller + /// Initializes the artboard, animations, state machines and controllers void _init(RiveFile file) { final artboard = widget.artboard != null ? file.artboardByName(widget.artboard!) @@ -96,13 +110,13 @@ class _RiveAnimationState extends State { throw FormatException('No animations in artboard ${artboard.name}'); } - // Create animations - // If there are no animations or state machines specified, select a default - // animation - final animationNames = - widget.animations.isEmpty && widget.stateMachines.isEmpty - ? [artboard.animations.first.name] - : widget.animations; + // Create animations If there are no animations, state machines, or + // controller specified, select a default animation + final animationNames = widget.animations.isEmpty && + widget.stateMachines.isEmpty && + widget.controllers.isEmpty + ? [artboard.animations.first.name] + : widget.animations; animationNames.forEach((name) => artboard .addController((_controllers..add(SimpleAnimation(name))).last)); @@ -117,7 +131,13 @@ class _RiveAnimationState extends State { } }); + // Add any user-created contollers + widget.controllers.forEach(artboard.addController); + setState(() => _artboard = artboard); + + // Call the onInit callback if provided + widget.onInit?.call(); } @override diff --git a/lib/src/widgets/rive_controller_animation.dart b/lib/src/widgets/rive_controller_animation.dart deleted file mode 100644 index 0066a25..0000000 --- a/lib/src/widgets/rive_controller_animation.dart +++ /dev/null @@ -1,115 +0,0 @@ -import 'package:flutter/widgets.dart'; -import 'package:rive/rive.dart'; -import 'package:rive/src/rive_core/artboard.dart'; - -enum _Source { - asset, - network, -} - -/// High level widget that plays an animation from a Rive file. If artboard or -/// animation are not specified, the default artboard and first animation fonund -/// within it are used. -class RiveControllerAnimation extends StatefulWidget { - /// The asset name or url - final String name; - - /// The type of source used to retrieve the asset - final _Source src; - - /// The name of the artboard to use; default artboard if not specified - final String? artboard; - - /// List of Rive controllers to attach - final List controllers; - - /// Fit for the animation in the widget - final BoxFit? fit; - - /// Alignment for the animation in the widget - final Alignment? alignment; - - /// Enable/disable antialiasing when rendering - final bool antialiasing; - - /// Widget displayed while the rive is loading - final Widget? placeHolder; - - /// Creates a new RiveControllerAnimation from an asset bundle - const RiveControllerAnimation.asset( - this.name, { - this.artboard, - this.controllers = const [], - this.fit, - this.alignment, - this.placeHolder, - this.antialiasing = true, - }) : src = _Source.asset; - - const RiveControllerAnimation.network( - this.name, { - this.artboard, - this.controllers = const [], - this.fit, - this.alignment, - this.placeHolder, - this.antialiasing = true, - }) : src = _Source.network; - - @override - _RiveControllerAnimationState createState() => - _RiveControllerAnimationState(); -} - -class _RiveControllerAnimationState extends State { - /// Rive controller - final _controllers = []; - - /// Active artboard - Artboard? _artboard; - - @override - void initState() { - super.initState(); - - if (widget.src == _Source.asset) { - RiveFile.asset(widget.name).then(_init); - } else if (widget.src == _Source.network) { - RiveFile.network(widget.name).then(_init); - } - } - - /// Initializes the artboard, animation, and controller - void _init(RiveFile file) { - final artboard = widget.artboard != null - ? file.artboardByName(widget.artboard!) - : file.mainArtboard; - - if (artboard == null) { - throw const FormatException('Unable to load artboard'); - } - if (artboard.animations.isEmpty) { - throw FormatException('No animations in artboard ${artboard.name}'); - } - - // Attach each controller to the artboard - widget.controllers.forEach(artboard.addController); - setState(() => _artboard = artboard); - } - - @override - void dispose() { - _controllers.forEach((c) => c.dispose()); - super.dispose(); - } - - @override - Widget build(BuildContext context) => _artboard != null - ? Rive( - artboard: _artboard!, - fit: widget.fit, - alignment: widget.alignment, - antialiasing: widget.antialiasing, - ) - : widget.placeHolder ?? const SizedBox(); -} diff --git a/pubspec.yaml b/pubspec.yaml index 451917e..3959da5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: rive description: Rive 2 Flutter Runtime. This package provides runtime functionality for playing back and interacting with animations built with the Rive editor available at https://rive.app. -version: 0.7.17 +version: 0.7.18 repository: https://github.com/rive-app/rive-flutter homepage: https://rive.app