1

My app contains a couple of pages. In the appbar I have a selfmade stateful widget with a badge that shows the number of new messages. When I swipe to refresh data the badge will run a small animation if the badge value is changed.

The problem is that the badge value comes from a scoped model. How do I run the animation from the scoped model class. I tried to let the scoped model class hold the animationController as well as a function. It works on the first and second screen. But when I am navigating back to the first page again and pull to refresh. It is like the animationController is in bad state.

Code in the scoped model:

Function _runNotificationAnimation;
set runNotificationAnimation(Function fun) => _runNotificationAnimation = fun;

void _setNotificationCount(int count) {
  _notificationCount = count;

  if (count > 0 && _runNotificationAnimation != null) {
    _runNotificationAnimation();
 }
 notifyListeners();
}

function that runs the animation

runAnim() {
    setState(() {
      controller.reset();
      controller.forward(from: 0.0);
    });
  }

Error from flutter:

[VERBOSE-2:shell.cc(184)] Dart Error: Unhandled exception: NoSuchMethodError: The method 'stop' was called on null. Receiver: null Tried calling: stop(canceled: true) 0 Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5) 1 AnimationController.stop (package:flutter/src/animation/animation_controller.dart:650:13) 2 AnimationController.value= (package:flutter/src/animation/animation_controller.dart:349:5) 3 AnimationController.reset (package:flutter/src/animation/animation_controller.dart:370:5) 4 NotificationIconState.runAnim (package:volvopenta/widgets/notificaton_icon.dart:38:16) 5 SettingsModel._setNotificationCount (package:volvopenta/scoped-models/settings-model.dart:57:7) 6 SettingsModel.updateAppData (package:volvopenta/scoped-models/settings-model.dart:185:5) 7 MyMachines.build... (package:volvopenta/pages/fleet.dart:83:27) 8<…>

Pablo Cegarra
  • 20,955
  • 12
  • 92
  • 110
  • `"the badge will run a small animation if the badge value is changed."` - what animation? is it a complex one or just fade out / fade in or the like? – pskink Nov 17 '18 at 09:57
  • It is a fade and scale transition. Sort of a heartbeat. A circle in a stack that is positioned under the badge. When the animation runs. The circle is scaled so it becomes visible and then it fades out. – user1295782 Nov 18 '18 at 10:17
  • see [AnimatedSwitcher](https://docs.flutter.io/flutter/widgets/AnimatedSwitcher-class.html) and its `transitionBuilder` property – pskink Nov 18 '18 at 15:26
  • That would work. Have not checked it up yet. – user1295782 Nov 20 '18 at 15:01

1 Answers1

1

Since your animation will be built in a stateful Widget, it is better to leave the animationController in that stateful Widget and move only the animation (Tween) in the model class. It is essential that you place the notifyListener(); in the controller.addListerner() and not at the end of the function.

class MyModel extends Model{
    Animation animation;
    runAnimation(controller) {
        animation = Tween(begin: 0,0, end: 
                400).animate(controller); 
        controller.forward();
        controller.addListener((){
           notifyListeners();
        });
     }
 }

You can call this function in your stateful widget as follows:

class _MyScreenState extends State<MyScreen> with 
                  SingleTickerProviderStateMixin{
   AnimationController controller;
   MyModel myModel = MyModel();

  @overide
  void initState(){
     super.initState();

     controller = AnimationController(duration: Duration(seconds: 2), vsync: 
     this);
     myModel.runAnimation(controller);
  }

  //dispose here

  @override
  Widget build(Buildcontext context){
     return ScopedModel<MyModel>(
     model: myModel,
     child: Scaffold(
         body: Text("Hello", style: TextStyle(fontSize: 13 * 
         controller.value)),
         ),
    );
  }
}
Loïc Fonkam
  • 2,284
  • 11
  • 25