Постоянный тикер во флаттере
Как получить постоянную галочку при каждом обновлении кадра. Например в игровом движке Flameupdate
метод вызывается примерно каждые 1/60
секунды и значение dt
с истекшим временем.
Я хочу реализовать одну простую анимацию, в которой вентилятор будет вращаться. Я хочу изменить его скорость вращения в зависимости от ввода пользователя. Я считаю, что при каждом тике я буду вращать изображение вентилятора / контейнер на фиксированное значение. По мере того, как пользователь увеличивает скорость, я увеличиваю множитель. Есть несколько вариантов, таких как использование двигателя Flame или Flare, но они кажутся излишними. Также я могу использоватьSingleTickerProviderMixin
но есть несколько накладных расходов, таких как перевернуть анимацию по завершении и перенаправить ее, и поэтому...
Я думаю, что будет простое решение, которое будет уведомлять меня при каждом обновлении кадра, которое происходит примерно каждые 1/60 секунды, и передавать мне прошедшее времяdt
(около 167 мс или около того).
3 ответа
Хороший способ сделать это (без виджетов анимации) - реализовать таймер с потоком; см. пример ниже:
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!'),
);
});
}
}
Я бы также не забыл реализовать обратный вызов dispose(), если вы скопируете этот код. Вы должны обязательно отменить () все работающие таймеры, чтобы предотвратить странное поведение, иначе они станут источником утечек памяти.
Таймер = NULL; не всегда требуется, но бывают ситуации, когда объект состояния будет содержать ссылку на сам таймер var, а также вызовет утечку памяти. Например, если вы захватите переменную таймера внутри тела обратного вызова таймера.
Пример:
@override
void dispose() {
timer?.cancel();
timer = null;
super.dispose();
}
Также вы можете использоватьStream.periodic()
.
Пример из документации:
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