Note that certain Rive features may not be supported yet for a particular runtime, or may require using the Rive Renderer.

For more details, refer to the feature support and choosing a renderer pages.

Overview

This guide documents how to use the Rive Flutter runtime to easily integrate Rive graphics in your Flutter apps.

Already using Rive Flutter? See our Migration Guide for information on adopting the latest version.

Quick start

See our quick start example that shows how to play a Rive graphic in Flutter.

Getting started

Follow the steps below to integrate Rive into your Flutter apps.

1

Add the Rive package dependency

Check out Rive’s pub.dev page to get the latest version.

# pubspec.yaml
dependencies:
  rive: ^0.14.0 # or latest version
2

Import the Rive package

Import the Rive runtime library in the file you’re looking to integrate Rive animations into.

import 'package:rive/rive.dart';

Consider doing a named import to avoid conflicts with other libraries:

import 'package:rive/rive.dart' as rive;
3

Initialize Rive

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());
}
4

Add a Rive widget

There are several ways to render Rive graphics in Flutter. We recommend using the RiveWidget, and optionally the RiveWidgetBuilder.

  • The RiveWidgetBuilder handles file loading, error states, and resource management automatically.
  • The RiveWidget is responsible for rendering the graphic and exposing common view configuration.
class ExampleRiveBuilder extends StatefulWidget {
  const ExampleRiveBuilder({super.key});

  @override
  State<ExampleRiveBuilder> createState() => _ExampleRiveBuilderState();
}

class _ExampleRiveBuilderState extends State<ExampleRiveBuilder> {
  late final fileLoader = FileLoader.fromAsset("assets/vehicles.riv", riveFactory: Factory.rive);

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

  @override
  Widget build(BuildContext context) {
    return RiveWidgetBuilder(
      fileLoader: fileLoader,
      builder: (context, state) => switch (state) {
        RiveLoading() => const Center(child: CircularProgressIndicator()),
        RiveFailed() => ErrorWidget.withDetails(
            message: state.error.toString(),
            error: FlutterError(state.error.toString()),
          ),
        RiveLoaded() => RiveWidget(
            controller: state.controller,
            fit: Fit.cover,
          )
      },
    );
  }
}
5

Loading from different sources

From Asset Bundle:

Make sure you add the Rive files to your asset bundle and reference them in pubspec.yaml:

# pubspec.yaml
assets:
    - assets/vehicles.riv
// Using FileLoader (with RiveWidgetBuilder)
final fileLoader = FileLoader.fromAsset("assets/vehicles.riv", riveFactory: Factory.rive);

// Using File directly
final file = await File.asset("assets/vehicles.riv", riveFactory: Factory.rive);

From URL:

// Using FileLoader (with RiveWidgetBuilder)
final fileLoader = FileLoader.fromUrl("https://cdn.rive.app/animations/vehicles.riv", riveFactory: Factory.rive);

// Using File directly
final file = await File.url("https://cdn.rive.app/animations/vehicles.riv", riveFactory: Factory.rive);

From Rive File:

// Using FileLoader (with RiveWidgetBuilder)
final fileLoader = FileLoader.fromFile(existingFile, riveFactory: Factory.rive);

Key components

RiveWidget

The RiveWidget is responsible for displaying Rive graphics.

Properties:

  • controller [required]: The RiveWidgetController that manages the Rive graphic
  • fit: How the artboard should fit within the widget (default: contain)
  • alignment: How the artboard should be aligned within the widget (default: center)
  • hitTestBehavior: How pointer events should be handled (default: opaque)
  • cursor: The cursor to display when hovering over the widget (default: defer)
  • layoutScaleFactor: Scale factor when using Fit.layout (default: 1.0)

RiveWidgetBuilder

The RiveWidgetBuilder is a higher-level widget that handles file loading, error states, and resource management automatically.

Properties:

  • fileLoader [required]: The FileLoader for loading the Rive file
  • builder [required]: Function that builds the widget based on state
  • artboardSelector: Which artboard to use (default: ArtboardDefault())
  • stateMachineSelector: Which state machine to use (default: StateMachineDefault())
  • dataBind: How to bind view model data (optional)
  • controller: Optional custom controller builder
  • onLoaded: Callback when Rive state is loaded
  • onFailed: Callback when Rive state fails to load

RiveWidgetController

The RiveWidgetController manages the graphic.

Creating a Controller:

// Using default artboard and state machine
final controller = RiveWidgetController(file);

// Specifying artboard and state machine
final controller = RiveWidgetController(
  file,
  artboardSelector: ArtboardSelector.byName("MyArtboard"),
  stateMachineSelector: StateMachineSelector.byName("MyStateMachine"),
);

Data Binding:

// Auto-bind with default view model instance
final viewModelInstance = controller.dataBind(DataBind.auto());

// Bind by specific instance
final viewModelInstance = controller.dataBind(DataBind.byInstance(myInstance));

// Bind by name
final viewModelInstance = controller.dataBind(DataBind.byName("MyViewModel"));

File loading

The FileLoader class provides a unified way to load Rive files from different sources.

Loading from Assets:

final fileLoader = FileLoader.fromAsset(
  "assets/vehicles.riv",
  riveFactory: Factory.rive,
);

Loading from URL:

final fileLoader = FileLoader.fromUrl(
  "https://example.com/animation.riv",
  riveFactory: Factory.rive,
);

Loading from Existing File:

final fileLoader = FileLoader.fromFile(
  existingFile,
  riveFactory: Factory.rive,
);

Or you can load files directly using the File class:

// Load from asset
final file = await File.asset("assets/vehicles.riv", riveFactory: Factory.rive);
// Load from URL
final file = await File.url("https://example.com/animation.riv", riveFactory:
Factory.rive);
// Load from path
final file = await File.path("/path/to/animation.riv", riveFactory: Factory.rive);
// Load from bytes
final file = await File.decode(bytes, riveFactory: Factory.rive);

Error handling

The Rive Flutter package provides specific exception types for different error scenarios:

  • RiveFileLoaderException: Thrown when file loading fails
  • RiveArtboardException: Thrown when artboard selection fails
  • RiveStateMachineException: Thrown when state machine selection fails
  • RiveDataBindException: Thrown when data binding fails

Resource management

Manual resource management (RiveWidget)

When using RiveWidget directly, you are responsible for managing all resources:

@override
void dispose() {
  // Dispose resources in reverse order of creation
  viewModelInstance.dispose();
  controller.dispose();
  file.dispose();
  super.dispose();
}

Automatic resource management (RiveWidgetBuilder)

When using RiveWidgetBuilder, the widget automatically manages most resources. You only need to dispose the file loader:

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

Because the resources are managed by the RiveWidgetBuilder, you will not be able to access the RiveWidgetController (and other state) after the widget is disposed. If you need to access the controller after the widget is disposed, consider creating the file and controller yourself.

The exception to this is the FileLoader, which you control. This loader can be reused across multiple RiveWidgetBuilder instances. The underlying File will only be loaded once. The File will be disposed when the FileLoader is disposed.

Specifying a renderer

When creating a Rive File or FileLoader, you need to specify a factory to use:

  • Factory.rive for the Rive renderer
  • Factory.flutter for the Flutter renderer (Skia or Impeller)

You can use different renderers for different graphics in your app.

Some considerations when choosing a renderer:

  • If you plan on showing many Rive graphics that are all drawing to different Rive widgets, consider using Factory.flutter to reduce the native overhead of allocating native render targets and textures.
  • If you are showing a complex graphic, consider using Factory.rive to take advantage of the Rive renderer’s optimizations.
  • Vector Feathering is only available with Factory.rive, so if you need that feature, use the Rive renderer.

For more information see Choosing a Renderer.

Troubleshooting

If you encounter issues with Rive in Flutter, consider the following:

  • Ensure you have called RiveNative.init() before using any Rive features.
  • Check the console for any error messages related to Rive.
  • Make sure your Rive files are correctly referenced in pubspec.yaml and exist in the specified paths.
  • If using RiveWidgetBuilder, ensure you handle all possible states (loading, loaded, failed) in the builder function.

Build errors

If you encounter build errors related to Rive, ensure that:

  • You have the correct version of the Rive package in your pubspec.yaml.
  • You have run flutter pub get to fetch the latest dependencies.

If you’re still having issues, please see the Troubleshooting section in the Rive Native documentation.

Manually building Rive native libraries

Rive automatically downloads the native libraries for you as part of the rive_native plugin.

However, if you need to manually build the native libraries, see the build section in the Rive Native documentation.

Next steps

Now that you have Rive integrated into your Flutter app, you can explore more advanced features like:

Resources

Rive Flutter:

Rive Native: