Skip to main content
N
6d ago

Rive animation in flutter with nested artboards.

I am trying to figure out the code for a rive animation with nested artboards. I made sure this is the path:

Inspecting Rive File: assets/rsvp3.riv

Root Artboard: Artboard

  • Nested Artboard: notgoingartboard

    • Animations: State Machine: notstate

      • Input Path: notgoingartboard -> notgoing_click (SMITrigger)

      • Input Path: notgoingartboard -> notgoing_turnoff (SMITrigger)

  • Nested Artboard: maybeartboard

    • Animations: State Machine: maybestate

      • Input Path: maybeartboard -> maybe_click (SMITrigger)

      • Input Path: maybeartboard -> maybe_turnoff (SMITrigger)

  • Nested Artboard: goingartboard

    • Animations: Animation: going

      • Input Path: goingartboard -> going_click (SMITrigger)

      • Input Path: goingartboard -> going_turnoff (SMITrigger)

this is how the rive looks like:

I can't figure out the code to show the nested artboards and for it to work.

3 replies
N
6d ago

By default the nested artboard names aren't exported for use at runtime. We do that to reduce the size of the .riv. If you need access to a nested artboard, go to the hierarchy in the parent artboard, right click the nested artboard and select Export Name. Notice that when you do that, the name changes from notgoingartboard to [notgoingartboard] . This should fix your problem.

Side note, sorry that the process for testing nested inputs is so tricky. We have a new system coming soon that's going to make it a lot easier.

N
(edited) 6d ago

Hi I did this and it does not solve my issue. Do you have the code that I can use for flutter? I did this but it does not work:

import 'package:flutter/material.dart';
import 'package:rive/rive.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: RiveButtonDemo(),
    );
  }
}

class RiveButtonDemo extends StatefulWidget {
  @override
  _RiveButtonDemoState createState() => _RiveButtonDemoState();
}

class _RiveButtonDemoState extends State<RiveButtonDemo> {
  SMIInput<bool>? notGoingClick;
  SMIInput<bool>? notGoingTurnOff;

  SMIInput<bool>? maybeClick;
  SMIInput<bool>? maybeTurnOff;

  SMIInput<bool>? goingClick;
  SMIInput<bool>? goingTurnOff;

  Artboard? rootArtboard;

  @override
  void initState() {
    super.initState();
    loadRiveFile();
  }

  Future<void> loadRiveFile() async {
    final riveFile = await RiveFile.asset('assets/rsvp3.riv');

    // Load Root Artboard
    rootArtboard = riveFile.artboardByName('Artboard');
    if (rootArtboard == null) {
      print('Root Artboard not found');
      return;
    }

    // Access Nested Artboards with their State Machines
    setupArtboardTriggers(riveFile, 'notgoingartboard', 'notstate', (inputMap) {
      notGoingClick = inputMap['notgoing_click'] as SMIInput<bool>?;
      notGoingTurnOff = inputMap['notgoing_turnoff'] as SMIInput<bool>?;
    });

    setupArtboardTriggers(riveFile, 'maybeartboard', 'maybestate', (inputMap) {
      maybeClick = inputMap['maybe_click'] as SMIInput<bool>?;
      maybeTurnOff = inputMap['maybe_turnoff'] as SMIInput<bool>?;
    });

    setupArtboardTriggers(riveFile, 'goingartboard', 'going', (inputMap) {
      goingClick = inputMap['going_click'] as SMIInput<bool>?;
      goingTurnOff = inputMap['going_turnoff'] as SMIInput<bool>?;
    });

    setState(() {});
  }

  void setupArtboardTriggers(
      RiveFile riveFile, String artboardName, String stateMachineName, Function(Map<String, SMIInput>) setupInputs) {
    final artboard = riveFile.artboardByName(artboardName);
    if (artboard != null) {
      final stateMachineController = StateMachineController.fromArtboard(artboard, stateMachineName);
      if (stateMachineController != null) {
        artboard.addController(stateMachineController);
        final inputs = {for (var input in stateMachineController.inputs) input.name: input};
        setupInputs(inputs);
      } else {
        print('StateMachineController not found for $artboardName with state machine $stateMachineName');
      }
    } else {
      print('Artboard $artboardName not found!');
    }
  }

  void toggleInput(SMIInput<bool>? input) {
    if (input != null) {
      input.value = !input.value; // Toggle the boolean value
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Rive Button Demo')),
      body: Center(
        child: rootArtboard == null
            ? CircularProgressIndicator()
            : Rive(
                artboard: rootArtboard!,
                fit: BoxFit.contain,
              ),
      ),
    );
  }
}
5d ago

Can you try using the getNumberInput method? Here are the docs for using inputs on nested artboards: https://rive.app/community/doc/rive-parameters/docHI9ASztXP

final volumeInput = artboard.getNumberInput('notgoing_click', 'notgoingartboard')!; 
volumeInput.fire()