32

I'm trying to listen to a variable change to execute some code. So the variable is a bool named reset. I want to execute something (say reset the animation controller) once the animation ends OR a button (from another widget) is pressed. Executing something when the animation ends works as once it ends AnimationStatus.dismissed will be its state and the listener will be called. This then allows me to use a callback function onCountdownexpire in order to set the variable reset accordingly and based on what it is set, execute some code in the if(widget.reset) block. So there is no need to listen for this case.

Problem:

However, lets say a button is pressed (in another widget) and I set the variable reset to true. I want the animation to stop and reset. I cannot now depend on the AnimationStatus listener as it only executes when there is a state change. I want it to reset during its state. So I have to somehow listen to the variable widget.reset.

I have done some research on this and found out that ValueNotifier might be a way to go but there are not a lot of examples on how to go about using it. Like how do I go about listening to it ?

Code:

class Countdown extends StatefulWidget {

  final VoidCallback onCountdownExpire;
  bool reset;
  Countdown(this.onCountdownExpire);

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

class CountdownState extends State<Countdown> with TickerProviderStateMixin {
  AnimationController controller;

  String get timerString {
    Duration duration = controller.duration * controller.value;
    return '${duration.inMinutes}:${(duration.inSeconds % 60).toString()}';
  }

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      vsync: this,
      duration: Duration(seconds: 2),
    )..addStatusListener((AnimationStatus status){
        if (status == AnimationStatus.dismissed) {
          debugPrint("Animation.dismissed");
          widget.onCountdownExpire();
          if (widget.reset) {
            widget.reset = false;
            controller.reverse(from: 1.0);
          } 
        }
    });
    controller.reverse(from: 1.0);
  }
  ... // omitted code
}

What I have tried but it does not seem to be working as expected:

class Countdown extends StatefulWidget {

  final VoidCallback onCountdownExpire;
  Countdown(this.onCountdownExpire);
  ValueNotifier reset = ValueNotifier(false);

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

class CountdownState extends State<Countdown> with TickerProviderStateMixin {
  AnimationController controller;

  @override
  void initState() {

    widget.reset.addListener(() {
      debugPrint("value notifier is true");
      controller.reverse(from: 1.0);
    });

    super.initState();

    controller = AnimationController(
      vsync: this,
      duration: Duration(seconds: 2),
    )..addStatusListener((AnimationStatus status){
        if (status == AnimationStatus.dismissed) {
          debugPrint("Animation.dismissed");
          widget.onCountdownExpire();
        }
    });
    controller.reverse(from: 1.0);
  }
  ... // omitted code
}

Update: The solution (above) was actually working, I just had to use something like this to notify the listener:

countdown.reset.notifyListeners();
// OR
countdown.reset.value = true;  
Rajdeep
  • 2,246
  • 6
  • 24
  • 51
  • use `ValueNotifier::addListener` method – pskink Jun 03 '19 at 06:17
  • @pskink Ok hi, I tried that but it does not seem to be working as expected (post updated). Am I implementing it correctly ? – Rajdeep Jun 03 '19 at 06:49
  • @pskink ok nvm i was calling it wrongly, I had to use something like `countdown.reset.notifyListeners(); `. Thanks for your help ! Post your answer and I'll accept it :) – Rajdeep Jun 03 '19 at 06:55
  • no, you dont need `notifyListeners` - if you call `countdown.reset = ...` the method `notifyListeners` will be called automagically - see `ValueNotifier` docs: *"When `value` is replaced with something that is not equal to the old value as evaluated by the equality operator ==, this class notifies its listeners."* – pskink Jun 03 '19 at 07:03
  • @pskink hmmm I tried `countdown.reset = ValueNotifier(true)` but it did not seem to update – Rajdeep Jun 03 '19 at 07:07
  • 3
    sorry, i mean `countdown.reset.value = ...` – pskink Jun 03 '19 at 07:07
  • @pskink ah its working now too (after I did `countdown.reset.value = true`). Thanks man ! – Rajdeep Jun 03 '19 at 07:09
  • sure, your welcome – pskink Jun 03 '19 at 07:10
  • If I do it like a this, I get warning: "must_be_immutable" for Countdown class, since it extends StatefulWidget which is immutable. – miloss Dec 25 '19 at 16:23

2 Answers2

25

OP already got an answer in the comments. I'm just typing it here so the question is correctly marked as answered.

Just notify the listener:

countdown.reset.notifyListeners();
// OR
countdown.reset.value = true;

Credit to @pskink

ambiguous58
  • 1,241
  • 1
  • 9
  • 18
1

Use of overwriting getter/setters

You can make use of the getter and setter functions.

In the example below we are printing happy birthday when the person's age changes:

class Person {
  int _age;

  Person(this._age);

  int get age => _age;
  
  set age(int newValue) {
    print("Happy birthday! You have a new Age.");
    //do some awsome things here when the age changes
    _age = newValue;
  }
}

The usage is exactly as you are used to:

final newPerson = Person(20);
  
print(newPerson.age); //20
newPerson.age = 21; //prints happy birthday
print(newPerson.age); //21
Paul
  • 1,349
  • 1
  • 14
  • 26
  • @KristiJorgji It's technically not "listening". But it has the same outcome, and sometimes even is more suitable for certain situations that might be searched up by "listening to variable change". I would say at least a considerable answer... – Paul May 12 '23 at 13:07
  • Yes it is true that it is not listening, but it does what the question owner asked to do. But I get it now makes sense why it got downvoted as he asked "listen" there is no listener or notifier mechanism in this solution but it is an imperative approach – Kristi Jorgji May 15 '23 at 15:16