2

How to get a persistent tick at every frame refresh time. For example in Flame game engine update method gets called at around every 1/60 seconds and a value dt with elapsed time is passed.

I want to implement one simple animation where a fan will rotate. I want to change its rotation speed depending on user input. My idea is that at every tick I will rotate the fan image/ container at a fixed value. As the user increases the speed I will increase the multiplier. There are few options like using the Flame engine or Flare, but they seem overkill. Also, I can use SingleTickerProviderMixin but there are few overheads like reverse the animation when finished and forwarded it and so...

I think there will be a simple solution, which will notify me at each frame refresh time that occurs at around every 1/60 seconds, and pass me the elapsed time dt (around 167 mS or so).

Epsi95
  • 8,832
  • 1
  • 16
  • 34
  • `AnimationController` is what you need, more [here](https://flutter.dev/docs/development/ui/animations/tutorial#animationcontroller) – pskink May 08 '20 at 11:09
  • If I use animation controller then I have to reverse and forward the animation. I did some projects using this. But I was asking if there is any simple solution, like flutter refreshes the frame (build method more specifically) at around every 1/60th of a second if there exists any callback kind of thing so that I can sync my action with that. – Epsi95 May 08 '20 at 11:27
  • a `Ticker` - but I don't really see any reason for using that low level mechanizm if you have ready to use `AnimationController` – pskink May 08 '20 at 11:42
  • So u r suggesting to have an animation controller of duration 1sec and every time I hit 1 sec I need to reverse it? Once I tried a reverse duration of 0 mS and forward duration of 1sec but it gave me an unpredictable result. It would be great if u provide one minimalist example where I can get a persistent tick and callback. – Epsi95 May 08 '20 at 14:34
  • 1
    `ctrl.repeat();` – pskink May 08 '20 at 14:46
  • oh didn't know about the repeat method, should do the work seems – Epsi95 May 08 '20 at 15:52
  • check other methods as well – pskink May 08 '20 at 15:54

2 Answers2

4

A nice way to do it (without Animation widgets), is to implement a Timer with a Stream; see the example below:

import 'package:flutter/material.dart';
import "dart:async";

const frequency = Duration(milliseconds: 50);

void main() => runApp(
      MaterialApp(
        home: Material(
          child: Center(
            child: Container(
              color: Colors.white,
              child: MyWidget(),
            ),
          ),
        ),
      ),
    );

class MyWidget extends StatefulWidget {
  MyWidgetState createState() => MyWidgetState();
}

class MyWidgetState extends State<MyWidget> {
  final StreamController<double> _streamer =
      StreamController<double>.broadcast();

  Timer timer;

  double _rotation = 0.0;

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

    timer = Timer.periodic(frequency, (t) {
      _rotation++;
      _streamer.add(1);
    });
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<double>(
        initialData: 0,
        stream: _streamer.stream,
        builder: (context, snapshot) {
          return Transform(
            transform: Matrix4.rotationZ(_rotation),
            child: Text('Hello, World!'),
          );
        });
  }
}
camillo777
  • 2,177
  • 1
  • 20
  • 20
  • that sounds promising, let me check – Epsi95 May 08 '20 at 15:49
  • while I don't think this fits the question, it's a useful way to provide an application wide seconds counter. If anyone lift this for their application, you should add a dispose method for the state: Cancel the timer, then dispose it. – Curt Eckhart Oct 03 '20 at 15:39
1

I would also make sure to implement the dispose() callback if you copy this code. You need to make sure to cancel() any running timers to prevent odd behaviors or they will become a source of memory leaks.

The timer = null; is not always needed, but there are situations where the state object will hold a reference to the timer var itself and also cause a memory leak. For example, if you capture the timer var inside the timer callback body.

Example:

@override
  void dispose() {
    timer?.cancel();
    timer = null;
    super.dispose();
  }
Curt Eckhart
  • 455
  • 5
  • 11