Version 0.14.0

This is a significant update for Rive Flutter. We’ve completely removed all of the Dart code that was used for the Rive runtime and replaced it with our underlying C++ Runtime. See the Rive Native for Flutter page for more details.

This has resulted in a numbers of changes to the underlying API, and a large portion of the code base that was previously accessible through Dart is now implemented in C++ through FFI.

What’s New in 0.14.0

This release of Rive Flutter adds support for:

  • Rive Renderer
  • Data Binding
  • Layouts
  • Scrolling
  • N-Slicing
  • Vector Feathering
  • All other features added to Rive that did not make it to the previous versions of Rive Flutter
  • Includes the latest fixes and improvements for the Rive C++ runtime
  • Adds prebuilt libraries, with the ability to build manually. See the rive_native package for more information
  • Removes the rive_common package and replaces it with rive_native

Now that Rive Flutter makes use of the core Rive C++ runtime, you can expect new Rive features to be supported sooner for Rive Flutter.

All your Rive graphics will still look and function the same as they did before.

Requirements

Dart and Flutter Versions

This release bumps to these versions:

sdk: ">=3.5.0 <4.0.0"
flutter: ">=3.3.0"

Required Setup

Important: You must call RiveNative.init at the start of your app, or before you use Rive. For example, in main.dart:

import 'package:rive/rive.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await RiveNative.init(); // Call init before using Rive
  runApp(const MyApp());
}

Migration Guide

Quick Migration Checklist

  1. ✅ Update your pubspec.yaml dependencies to use version 0.14.0 or later
    dependencies:
      rive: ^0.14.0 # or latest version
    
  2. ✅ Add RiveNative.init() to your main() function, or call before using Rive.
  3. ✅ Replace Rive and RiveAnimation widgets with RiveWidget or RiveWidgetBuilder
  4. ✅ Update your controllers to use the new API, see RiveWidgetController
  5. ✅ Review and update any custom asset loading code
  6. ✅ Test your graphics and interactions

Removed Classes

The following classes have been completely removed:

  • Rive and RiveAnimation widgets → Use RiveWidget and RiveWidgetBuilder
  • RiveAnimationController and its subclasses → Use RiveWidgetController, SingleAnimationPainter, and StateMachinePainter
  • OneShotAnimation and SimpleAnimation → Use SingleAnimationPainter to play individual animations
  • StateMachineController → Use StateMachine instead (can be accessed via RiveWidgetController.stateMachine)
  • RiveEvent → Replaced with Event
  • SMITrigger → Replaced with TriggerInput
  • SMIBool → Replaced with BooleanInput
  • SMINumber → Replaced with NumberInput
  • FileAssetLoader → Replaced with optional callback when creating a File

Loading Rive Files

RiveFile has been removed and replaced with File. Important changes:

New API
final file = await File.decode(bytes, factory: Factory.rive);
final artboard = file.defaultArtboard();
final artboard = file.artboard('MyArtboard');

The provided Factory determines the renderer that will be used. Use Factory.rive for the Rive renderer or Factory.flutter for the shipped Flutter renderer (Skia or Impeller).

Vector Feathering only works with the Rive Renderer.

Key Changes:

  • Creating a Rive File now requires a factory (Factory.rive or Factory.flutter)
  • Replace RiveFile.import with File.decode() which returns a Future<File>
  • Replace mainArtboard with defaultArtboard()
  • Replace artboardByName(name) with artboard(name)
  • Replace RiveFile.network with File.url
  • Replace RiveFile.file with File.path

Widget Migration

See the updated example app for a complete migration guide, including how to use the new RiveWidget and RiveWidgetBuilder APIs.

Old WidgetNew WidgetNotes
Rive/RiveAnimationRiveWidget/RiveWidgetBuilderDirect replacement
Using RiveWidgetBuilder
class SimpleAssetAnimation extends StatefulWidget {
    const SimpleAssetAnimation({Key? key}) : super(key: key);

    @override
    State<SimpleAssetAnimation> createState() => _SimpleAssetAnimationState();
}

class _SimpleAssetAnimationState extends State<SimpleAssetAnimation> {
    late final fileLoader = FileLoader.fromAsset(
        'assets/off_road_car.riv',
        riveFactory: Factory.rive,
    );

    @override
    void dispose() {
        fileLoader.dispose();
        super.dispose();
    }

    @override
    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: const Text('Simple Animation'),
            ),
            body: Center(
                child: RiveWidgetBuilder(
                    fileLoader: fileLoader,
                    builder: (context, state) => switch (state) {
                        RiveLoading() => const CircularProgressIndicator(),
                        RiveFailed() => Text('Failed to load: ${state.error}'),
                        RiveLoaded() => RiveWidget(
                            controller: state.controller,
                            fit: Fit.cover,
                        ),
                    },
                ),
            ),
        );
    }
}

Controller Migration

Old ControllerNew ControllerNotes
RiveAnimationControllerRiveWidgetControllerMain controller for widgets
StateMachineControllerStateMachineDirect state machine access
OneShotAnimation and SimpleAnimationSingleAnimationPainterFor individual animations

Example using the new RiveWidgetController:

Using RiveWidgetController
final file = await File.asset('assets/off_road_car.riv', riveFactory: Factory.rive);
final controller = RiveWidgetController(file!);
final artboard = controller.artboard; // access the loaded artboard
final viewModelInstance = controller.dataBind(DataBind.auto()); // auto data binding

Optionally specify which Artboard and State Machine to use:

Specifying Artboard and State Machine
final file = await File.asset('assets/off_road_car.riv', riveFactory: Factory.rive);
final controller = RiveWidgetController(
  file,
  artboardSelector: ArtboardSelector.byName('Main'),
  stateMachineSelector: StateMachineSelector.byName('State Machine 1'),
);

Handling State Machine Inputs

Consider using Data Binding for more advanced use cases

StateMachineController has been removed and replaced with StateMachine. Important changes:

State Machine Inputs: New API
stateMachine.trigger('myTrigger');
stateMachine.boolean('myBool');
stateMachine.number('myNumber');

You can access the stateMachine from the RiveWidgetController:

final controller = RiveWidgetController(file);
final stateMachine = controller.stateMachine;

It is recommended to manually dispose inputs when no longer needed: input.dispose()

Nested Inputs

You can access nested inputs by providing an optional path parameter:

Nested Inputs
stateMachine.boolean('myBool', path: 'nested/path');
stateMachine.number('myNumber', path: 'nested/path');
stateMachine.trigger('myTrigger', path: 'nested/path');

Handling Rive Events

Consider using Data Binding instead of events for more advanced use cases.

RiveEvent has been removed and replaced with Event. Event is a sealed class with two options:

  • OpenUrlEvent
  • GeneralEvent

Registering an event listener:

Rive Events: New API
// New API
final controller = RiveWidgetController(_riveFile!);
controller?.stateMachine.addEventListener(_onRiveEvent);

void _onRiveEvent(Event event) {
    // Do something with the event
}

Accessing properties returns Map<String, CustomProperty>. CustomProperty is also a sealed class with options:

  • CustomNumberProperty
  • CustomBooleanProperty
  • CustomStringProperty

All of these have a value field. On the Event class, there are convenient accessors:

// Convenient accessors
event.property(name);           // Returns a CustomProperty
event.numberProperty(name);     // Returns a CustomNumberProperty
event.booleanProperty(name);    // Returns a CustomBooleanProperty
event.stringProperty(name);     // Returns a CustomStringProperty

Layout Changes

BoxFit → Fit

Previously we used Flutter’s BoxFit class. Now we use our own Fit which includes an extra option:

// Old API
BoxFit.contain

// New API
Fit.contain
Fit.layout  // New option for layout-based fitting

Asset Loading Changes

The FileAssetLoader class and all its subclasses have been removed:

  • CDNAssetLoader
  • LocalAssetLoader
  • CallbackAssetLoader
  • FallbackAssetLoader
Out-of-band Asset Loading
Out-of-band Asset Loading: New API
// New API
assetLoader: (asset, bytes) { /* sync work only but can call async functions */ }
riveFactory.decodeImage(bytes) // or asset.decode(bytes)
asset.renderImage(someImage) // returns bool for success

Key Changes:

  • assetLoader can no longer be an asynchronous lambda
  • ImageAsset.parseBytes(bytes)riveFactory.decodeImage(bytes) or asset.decode(bytes)
  • FontAsset.parseBytes(bytes)riveFactory.decodeFont(bytes) or asset.decode(bytes)
  • AudioAsset.parseBytes(bytes)riveFactory.decodeAudio(bytes) or asset.decode(bytes)
  • ImageAsset.image = valueImageAsset.renderImage(value) (returns boolean)
  • FontAsset.font = valueFontAsset.font(value) (returns boolean)
  • AudioAsset.audio = valueAudioAsset.audio(value) (returns boolean)

Text Run Updates

We recommend using Data Binding instead to update text at runtime.

It’s no longer possible to access a TextValueRun object directly. Use these methods instead to access the String value:

Get/Set Text Run Value
final controller = RiveWidgetController(riveFile);
final artboard = controller.artboard;

// Get a text run value
artboard.getText(value)
artboard.getText(value, path: path)

// Set a text run value
artboard.setText(value)
artboard.setText(value, path: path)

Known Missing Features

These features are not available in v0.14.0 but may be added in future releases:

  • Automatic Rive CDN asset loading
  • speedMultiplier
  • useArtboardSize
  • clipRect
  • isTouchScrollEnabled
  • dynamicLibraryHelper

Removed Code Paths

All of the “runtime” Dart code has been removed from these paths:

  • src/controllers
  • src/core
  • src/generated
  • rive_core
  • utilities

Getting Help

If you encounter issues during migration:

  1. Check the Rive Flutter documentation
  2. Review the Data Binding guide
  3. Visit the Rive community forums
  4. Report issues on the GitHub repository