2d-inc / Flare-Flutter

Load and get full control of your Rive files in a Flutter project using this library.
https://rive.app/
MIT License
2.55k stars 469 forks source link

Can't get rotation to take effect #221

Closed davystrong closed 4 years ago

davystrong commented 4 years ago

I can't get the rotation I set to take effect. I tried to set the rotation inside my controller (extending FlareControls) but it doesn't update unless I play an animation. As the change is very small, I don't want to animate. Any suggestions?

umberto-sonnino commented 4 years ago

It sounds like your code might not be activating the controller properly. Could you post it, together with your Rive file?

davystrong commented 4 years ago

The code:

class HourHand extends StatefulWidget {
  const HourHand({Key key, this.time, this.color}) : super(key: key);
  final DateTime time;
  final Color color;

  @override
  _HourHandState createState() => _HourHandState();
}

class _HourHandState extends State<HourHand> {
  _HourController hourController = _HourController();

  @override
  Widget build(BuildContext context) {
    hourController.time = widget.time;
    return FlareActor(
      'assets/animations/HourHand.flr',
      color: widget.color,
      controller: hourController,
    );
  }
}

class _HourController extends FlareControls {
  FlutterActorArtboard artboard;

  @override
  void initialize(FlutterActorArtboard artboard) {
    super.initialize(artboard);
    this.artboard = artboard;
  }

  set time(DateTime time) {
    if (artboard != null) {
      ActorBone baseAngleBone = artboard.getNode('BaseAngle') as ActorBone;
      baseAngleBone.rotation =
          (time.hour * 30 + time.minute * 0.5 + time.second / 120 - 90) /
              180 *
              pi;
      //This is weird. The rotation doesn't update unless I play an animation
      play('Idle');
    }
  }
}

Link to the rive file: https://rive.app/a/davystrong/files/flare/hour-hand-2

umberto-sonnino commented 4 years ago

If you take a look at the play() function in FlareControls, it adds the animation to the list of animations controlled by FlareControls and activates the Controller itself.

The flag contained in the ValueNotifier isActive is necessary for FlareActor to know that the controller is indeed active, and marks FlareActor for painting. So instead of playing the idle animation, you can just do:

  set time(DateTime time) {
    if (artboard != null) {
      ActorBone baseAngleBone = artboard.getNode('BaseAngle') as ActorBone;
      baseAngleBone.rotation =
          (time.hour * 30 + time.minute * 0.5 + time.second / 120 - 90) /
              180 *
              pi;
      isActive.value = true;
    }
  }

  @override
  bool advance(FlutterActorArtboard artboard, double elapsed) {
    // De-activate the controller, and stop advancing.
    isActive.value = false;
    return false;
  }
davystrong commented 4 years ago

Great, that seems to have worked! I hadn't realized I could change the value of isActive. Thanks for your help!