Epsi95
Epsi95

Reputation: 9047

Persistent Ticker in Flutter

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).

Upvotes: 4

Views: 4185

Answers (3)

Eshfield
Eshfield

Reputation: 506

Also you can use Stream.periodic().

Example from the documentation:

final stream = Stream<int>.periodic(
  const Duration(seconds: 1),
  (count) => count * count,
).take(5);

stream.forEach(print); // Outputs event values 0,1,4,9,16 every second

Upvotes: 0

Curt Eckhart
Curt Eckhart

Reputation: 495

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();
  }

Upvotes: 2

camillo777
camillo777

Reputation: 2367

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!'),
          );
        });
  }
}

Upvotes: 5

Related Questions