60fps, 120fpsというワードを知らない
昔のFlutterの本を読んでいて、アニメーションがスムーズでなかったり、反応が遅かったりする話題が気になりました。
UIのパフォーマンスを見る際に重要なのが、フレームレートなるものだそうです。フレームレートとは、1秒間に見せるフレームの数です。
パラパラ漫画をイメージするとわかりやすいそうです。
参考になりそうな情報:
https://app-best.jp/articles/description_fps/
学習内容 Flutter は、1 秒あたり 60 フレーム (fps) のパフォーマンス、または 120 Hz 更新が可能なデバイスで 120 fps のパフォーマンスを提供することを目指しています。60 fps の場合、フレームは約 16 ミリ秒ごとにレンダリングする必要があります。UI がスムーズにレンダリングされないと、ジャンクが発生します。たとえば、時々、フレームのレンダリングに 10 倍の時間がかかるため、フレームがドロップされ、アニメーションが目に見えてぎくしゃくします。
Flutter フレームワークは、60fps でスムーズでないアプリケーションを作成しにくいように設計されています。多くの場合、ジャンクが発生するのは、単純なバグが原因で、フレームごとに必要以上に UI が再構築されるためです。ウィジェット再構築プロファイラーは、このような種類のバグによるパフォーマンスの問題をデバッグして修正するのに役立ちます。
こんなコードを書くとパフォーマンスが下がるかも?
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
enum ColorSchemeType {
light,
dark,
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
// lateをAnimationControllerにつけると、初期化を遅らせることができる。..repeat()で繰り返しアニメーションを行う。
late final AnimationController _controller = AnimationController(
duration: const Duration(seconds: 10),
vsync: this,
)..repeat();
// AnimationControllerを破棄する必要があるので、dispose()をオーバーライドする。
// @override
// void dispose() {
// _controller.dispose();
// super.dispose();
// }
int _counter = 0;
ColorSchemeType _colorSchemeType = ColorSchemeType.light;
void _incrementCounter() {
setState(() {
_counter++;
});
}
void _toggleTheme() {
setState(() {
_colorSchemeType = _colorSchemeType == ColorSchemeType.light
? ColorSchemeType.dark
: ColorSchemeType.light;
});
}
@override
Widget build(BuildContext context) {
final isLightTheme = _colorSchemeType == ColorSchemeType.light;
final theme = ThemeData(
brightness: isLightTheme ? Brightness.light : Brightness.dark,
colorScheme: isLightTheme
? ColorScheme.fromSeed(seedColor: Colors.deepPurple)
: const ColorScheme.dark(),
useMaterial3: true,
);
return MaterialApp(
title: 'Flutter Demo',
theme: theme,
home: Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(isLightTheme ? Icons.dark_mode : Icons.light_mode),
onPressed: _toggleTheme,
),
],
backgroundColor: theme.colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: theme.textTheme.headlineMedium,
),
Center(
child: AnimatedBuilder(
animation: _controller, // AnimationControllerを渡す。
child: Container(
width: 200.0,
height: 200.0,
color: Colors.green,
child: const Center(
child: Text('くるくる回っちゃうもんね〜'),
),
),
builder: (BuildContext context, Widget? child) {
// Transform.rotateで回転させる。
return Transform.rotate(
angle: _controller.value * 2.0 * math.pi,
child: child,
);
},
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
),
);
}
}
何度も赤い棒線が出てきた、ジャンクが多いことになります。 一瞬で消えたので、スクリーンショットに撮れませんでした💦
最後に
今回は、Flutterのフレームレートについてお勉強してみました。Flutterにはパフォーマンスを良くするために、推奨する方法があるようなので、それに従いましょう。
学習内容 Flutter は、1 秒あたり 60 フレーム (fps) のパフォーマンス、または 120 Hz 更新が可能なデバイスで 120 fps のパフォーマンスを提供することを目指しています。60 fps の場合、フレームは約 16 ミリ秒ごとにレンダリングする必要があります。UI がスムーズにレンダリングされないと、ジャンクが発生します。たとえば、時々、フレームのレンダリングに 10 倍の時間がかかるため、フレームがドロップされ、アニメーションが目に見えてぎくしゃくします。