Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does AnimationController needs a vsync?

When using AnimationController, what is the purpose of that vsync parameter?

class Example extends StatefulWidget {
  @override
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> with SingleTickerProviderStateMixin {
  AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this, // Why do we need this?
    );
  }

  // ...
}
like image 486
Rémi Rousselet Avatar asked Apr 05 '20 08:04

Rémi Rousselet


People also ask

What is vsync in animation Flutter?

What is vsync ? Vsync basically keeps the track of screen, so that Flutter does not renders the animation when the screen is not being displayed.

How is AnimationController different from timer?

Timer is unrelated to Flutter, and is just a timer like you'd fine in any other language. On the other hand, AnimationController (and Ticker , its equivalent of Timer ) is Flutter specific. The difference with a Timer is that, by using AnimationController , the "ticker" can be muted, slowed, or mocked.

What is Tickerproviderstatemixin?

Provides Ticker objects that are configured to only tick while the current tree is enabled, as defined by TickerMode. To create an AnimationController in a class that uses this mixin, pass vsync: this to the animation controller constructor whenever you create a new animation controller.

What is the refresh rate of our animation in Flutter?

Internally, Flutter uses a scheduler that renders the screen at 60 frames per second.


1 Answers

AnimationController's vsync parameter has one purpose: Controlling the progress of the animation based on external factors.

There are typically three main usages:

  • devtools like "slow animations", which reduce the speed of AnimationControllers by 50%.
  • widget testing. By using vsync, this allows tests to skip frames to target a very specific state of the animation. This is both precise and doesn't involve waiting for real-time.
  • it allows animations to be "muted" when the widget associated with the SingleTickerProviderStateMixin is not visible anymore

The last scenario is the main reason why our widgets need to that SingleTickerProviderStateMixin. Knowing what widget is associated with the animation matters. We can't just use a TickerProvider obtained from the root widget of our application.

Through that vsync, this will avoid scenarios where our widget is no longer visible (for example if another route is pushed on the top of it), but the animation is still playing and therefore makes our screen to keep refreshing

A way of seeing that behavior is by using the "performance overlay" devtool combined with widgets like CircularProgressIndicator, which internally uses AnimationController.

If we use Opacity to hide our indicator (which doesn't pause animations):

Opacity(
  opacity: 0,
  child: CircularProgressIndicator(),
)

Then the performance overlay shows that our screen keeps refreshing:

opacity performance overlay

Now, if we add a TickerMode (implicitly done by widgets like Visibility and Navigator), we can pause the animation, which stops the unnecessary refresh:

Opacity(
  opacity: 0,
  child: TickerMode(
    enabled: false,
    child: CircularProgressIndicator(),
  ),
),

muted

like image 85
Rémi Rousselet Avatar answered Oct 21 '22 03:10

Rémi Rousselet