体験方法
- Flutterの低レイヤーには、Widgetの描画を制御するクラスが存在する
- SchedulerBindingというクラス
- このクラスはシングルトン実装で、contextなどの情報を持たなくても、同一のインスタンスにアクセスできる
- この同一インスタンスに対してコールバック関数を注入することで、擬似的なアニメーションが実装できる
- 具体的には、画面が再描画されるたびに注入したコールバック関数を実行し、Stateの値を変更していくというもの
- シングルトン実装なため、コールバック関数の削除は絶対に必要となる(コントローラーのDisposeと同じ)
コード
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
void main() {
runApp(MaterialApp(home: const ScheduleBindingScreen()));
}
class ScheduleBindingScreen extends StatefulWidget {
const ScheduleBindingScreen({super.key});
@override
State<ScheduleBindingScreen> createState() => _ScheduleBindingScreenState();
}
class _ScheduleBindingScreenState extends State<ScheduleBindingScreen> {
double angle = 0.0;
int? animationId;
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
void _start() {
animationId = SchedulerBinding.instance.scheduleFrameCallback((timeStamp) {
_repeat();
});
}
void _repeat() {
animationId = SchedulerBinding.instance.scheduleFrameCallback((timeStamp) {
setState(() {
angle += 0.01;
});
_repeat();
});
}
void _stop() {
if(animationId != null){
SchedulerBinding.instance.cancelFrameCallbackWithId(animationId!);
setState(() {
animationId = null;
});
}
}
@override
Widget build(BuildContext context) {
final screen = Scaffold(
appBar: AppBar(title: Text('ScheduleBindingTets'),),
body: SafeArea(child: Center(child: Transform.rotate(angle: angle, child: Container(width: 100, height: 100, color: Colors.blue,),),),),
floatingActionButton: FloatingActionButton(onPressed: () {
if(animationId == null) {
_start();
} else {
_stop();
}
},
child: animationId == null ? Icon(Icons.play_arrow) : Icon(Icons.stop)
),
);
return screen;
}
}
animatonId = SchedulerBinding.instance.scheduleFrameCallBack();
この関数は、コールバック関数を注入した際に、その関数に対して一つの値を付与する。
この値を使って、コールバック関数を削除する。
参考