【Flutter】X(旧Twitter)のようにローディング表示したい
| ローディング中 | 描画後 |
|---|---|
![]() |
![]() |
要約
X(旧Twitter)のタイムラインでよく見る「グレーの骨格(スケルトン)+ シマー」なローディングを、「skeletonizer」を使って最小コードで実装します。既存レイアウトをそのまま「骨格化」できるので、別途ローディング用UIを作る手間が激減します。加えて、ダークテーマ、スイッチアニメーション、Sliver対応、パフォーマンスの注意点まで一気に解説します。
対象
- X(旧Twitter)風のローディングを導入したいFlutterエンジニア
- 初歩的な使い方を知りたい人(※Riverpod/BLoC等でも応用可)
- シマーをウィジェットに乗せたい人
問題設定
- APIレスポンス待ちの間、CircularProgressIndicatorだけだとUXが悪い
- ローディング専用UIを別途作るのは手間
- ダークモードやリスト/Sliverでも一貫した表現にしたい
これらの課題を、既存UIを自動変換して骨格化するskeletonizerで解決します。骨格化(skeletonize)は、既存レイアウトを「同じレイアウトのまま」灰色のボーン(骨)に置き換え、既定ではシマーを適用します。
解決アプローチ
骨格化
以下、FloatingActionButtonでListViewを表示したり、骨格化したものを表示したりする実装例です。
ポイントは3点!
Skeletonizer()を使うのと、enabledプロパティにbool値を渡すのと、Loading中でもダミーのリストデータを渡すこと。
最後が忘れがちなので要注意です。
また、skeletonizerはダミー表示用のUtilityクラスも用意されているのでそちらも要チェックです。
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Skeletonizer Demo')),
floatingActionButton: Padding(
padding: const EdgeInsets.only(bottom: 0, right: 4),
child: Padding(
padding: const EdgeInsets.only(bottom: 110),
child: FloatingActionButton(
child: Icon(
_enabled
? Icons.hourglass_bottom_rounded
: Icons.hourglass_disabled_outlined,
),
onPressed: () {
setState(() {
_enabled = !_enabled;
});
},
),
),
),
body: Skeletonizer(
enabled: _enabled,
enableSwitchAnimation: true,
child: ListView.builder(
itemCount: 6,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text('Item number $index as title'),
subtitle: const Text('Subtitle here'),
trailing: const Icon(Icons.ac_unit, size: 32),
),
);
},
),
),
);
}
}
ダークモードでの見た目
ライト・ダークモードでの見た目にも一貫性を持たせられるよう、デフォルトでこのパッケージが用意してくれてるSkeletonizerConfigData.dark()があります。
以下参考実装です。
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Skeletonizer Demo',
theme: ThemeData(extensions: const [SkeletonizerConfigData()]),
darkTheme: ThemeData(
brightness: Brightness.dark,
extensions: const [SkeletonizerConfigData.dark()],
),
home: const SkeletonizerDemoPage(),
);
}
}
よくあるハマりどころ
空リストだと骨格が出ない
skeletonizerは「既存レイアウトを骨格化」する仕組み。つまり描画するレイアウトが必要です。ロード中は、ダミーデータで形だけ用意しておくと骨格化されます。
コンテナの扱いを調整したい
「コンテナは骨格化せず中身だけ骨格化したい」場合、ignoreContainersを使うと実現できます。
切替時にガクつく
enableSwitchAnimationにtrueを指定することである程度解消します。
まとめ
Skeletonizerで既存UIを自動骨格化し、より良いUXを目指していきましょう。空のレイアウトでは骨格が出ない部分は注意し、ロード中はダミーデータで形を作りましょう。これでは物足りない時はShimmerパッケージを検討するのも良いでしょう。以上Skeletonizerパッケージの紹介でした。


Discussion