Flutterでスクロールバーを表示させたい場合、いくつか選択肢がある。が、「常にスクロールバーを表示させたい」なーと思ってScrollBar
にisAlwaysShown: true
を設定すると、なぜか途端にエラーの山にのまれて大変なことになるので、迷わないように定型化してみた。
結論
final _scrollController = ScrollController(); // ScrollControllerは必須
// 中略
Scrollbar(
isAlwaysShown: true,
controller: _scrollController, // <- 同じScrollControllerを配置
child: SingleChildScrollView(
controller: _scrollController, // <- 同じScrollControllerを配置
// 以下、ScrollView内に配置したいWidget
child: ListView(
// ListViewを配置する場合、以下2行は必須
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: [
// ...
]
)
)
)
実際の動作は以下のDartPadで確認できる。
https://dartpad.dartlang.org/?id=d1330072fc1e7f2b9c9af52a1bd87edf&null_safety=true
解説
特にListViewと併用する場合などに詰まってしまうパターンがよくあると思うので、まとめてテンプレ化した。
解説は以下参考ページに詳しく書かれているので割愛。isAlwaysShown: true
する場合もしない場合も、このテンプレを基本にしておくと役立つと思うので、まとめてWrapしたWidgetにしておくと便利かもしれない。
同じページに複数のスクロール画面がある場合は、もちろん各場所でScrollControllerは分ける必要があるけれど、その場合もScrollbar
とSingleChildScrollView
では共通のScrollControllerが必要。
カスタムWidgetにまとめる
ということで、こんな感じにWidget化しておくと使いやすい。使うときはSimpleScrollView
あるいはScrollListView
を呼べばよいので迷いがない。
import 'package:flutter/material.dart';
void main() => runApp(App());
class SimpleScrollView extends StatelessWidget {
SimpleScrollView({required this.child, this.isAlwaysShown = true});
final Widget child;
final bool isAlwaysShown;
final _scrollController = ScrollController();
@override
Widget build(BuildContext context) {
return Scrollbar(
isAlwaysShown: isAlwaysShown,
controller: _scrollController,
child: SingleChildScrollView(
controller: _scrollController,
child: child,
));
}
}
class ScrollListView extends StatelessWidget {
ScrollListView({required this.children});
final List<Widget> children;
@override
Widget build(BuildContext context) {
return SimpleScrollView(
child: ListView(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
children: children));
}
}
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Material(
child: Scaffold(
body: ScrollListView(children: [
for (var i = 0; i < 50; i += 1) ListTile(title: Text("Item $i"))
]),
),
));
}
}
DartPad
https://dartpad.dartlang.org/?id=bbd86b3e8515a4559255238b7588bf95&null_safety=true
参考