概要
Flutterで縦に長いページを作成する場合、任意の場所まで自動でスクロールさせたいユースケースがあると思います。
デフォルトSDKで一応用意されているもののListViewの位置指定をindex単位で指定できません。
今回はindex単位で遷移できる【scroll_to_index】の具体的な実装方法を整理したいと思います。
なお、【scroll_to_index】の弱点としては、indexを利用した遷移についてはanimationのみサポートしていることでしょうか(2021年10月時点)。
index単位でジャンプさせたい場合は、別のプラグイン採用をご検討いただければと思います。
スクロールについては、前後編を予定しています。
| 内容
---|---
前編(本記事)|【同一Widget内】で、任意のスクロール場所へ遷移する方法
後編|【表示と異なるWidget】で、任意のスクロール場所へ遷移する方法
※具体的にはAppBarを押すとページ最上部に遷移する(イメージ:Twitter, Instagramなど)
実装イメージ
環境
$ flutter --version
Flutter 2.5.1 • channel stable • https://github.com/flutter/flutter.git
Framework • revision ffb2ecea52 (3 weeks ago) • 2021-09-17 15:26:33 -0400
Engine • revision b3af521a05
Tools • Dart 2.14.2
pubspec.yaml
dependencies:
# ✨✨✨↓追加✨✨✨
scroll_to_index: ^2.1.0
実装
こちらの記事を参考にしつつ、実際に組み込んでみました。
注意してほしい箇所はコメントに記載しているので、その辺りも見ていただければと。
GitHubにも全文公開しているのでご参考まで
class ScrollWidget extends StatelessWidget {
const ScrollWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final controller = AutoScrollController();
return ListView.builder(
controller: controller,
/// とりあえず100個だけ表示するように実装
itemCount: 100,
itemBuilder: (context, index) {
return AutoScrollTag(
key: ValueKey(index),
controller: controller,
index: index,
child: Column(
children: [
/// ListViewの先頭のみ、ボタンを設置する実装(ここは正直あんまり参考にしない方がいいかも?)。
if (index == 0)
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
/// ボタンを押したら任意の場所にジャンプできる。50の値を適宜変更してください。
controller.scrollToIndex(
50,
/// beginがListのindexの頭に表示される。他に、middleとendが存在する
preferPosition: AutoScrollPosition.begin,
);
},
child: const Text('50番目にジャンプ'),
),
),
SizedBox(
width: double.infinity,
height: 80,
/// 行頭に遷移されることがわかりやすいようにCardウィジェットを採用しています。適宜変更してください。
child: Card(
child: Text(
'$index',
style: const TextStyle(fontSize: 24),
),
),
),
],
),
);
},
);
}
}
そこまで長くないので呼び出し元のサンプルコードも掲載します。
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Sample of Scroll to Jump'),
),
/// 呼び出し元のメソッド
body: const ScrollWidget(),
),
);
}
}