FlutterでBottomNavigationBarのアイテムを押した時にスクロールを一番上に戻す
twitterなど、よくあるBottomNavigationを押したときにスクロールをトップに戻す実装について紹介します。
完成物
実装方法は簡単です。
1、同じ要素のButtomNavigationを検知する
2、スクロールリスナーを設定する
3、スクロールリスナー経由でスクロールを一番上に戻す
BottomNavigationの実装については下記をご覧ください
BottonNavigationの状態を残したい場合は下記の方法が有効だと思います
https://www.shogogeek.com/entry/20190221/1550745000
1、同じ要素のButtomNavigationを検知する
BottomNavigationのタッチイベントで検知します
void _selectedTab(int index) {
if (_currentTab == index) {
// ここにスクロールを戻す処理を書く
} else {
setState(() {
_currentTab = index;
});
}
}
2、スクロールリスナーを設定する
まずはScrollControllerのインスタンスを作成
final ScrollController _homeController = ScrollController();
作成したらスクロールするWidgetにControllerを設定します。
この例では CustomScrollViewにControllerを設定していますが、ListViewや、SingleChildScrollViewでも同じです。
body: CustomScrollView(
controller: widget._controller,
slivers: <Widget>[
SliverStaggeredGrid.countBuilder(
crossAxisCount: 2,
itemBuilder: (context, index) {
String name = index.toString();
return _itemWidget(index, "assets/$name.png");
},
staggeredTileBuilder: (int index) => const StaggeredTile.fit(1),
itemCount: 6,
),
],
),
3、スクロールリスナー経由でスクロールを一番上に戻す
次にスクロールを一番を一番上に戻す処理をかけば完成です。
void _selectedTab(int index) {
if (_currentTab == index) {
_homeController.animateTo(
0.0,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 300),
);
setState(() {
_currentTab = index;
});
}
}
補足
BottomNavigationItemの状態によって別のクラスに分けている場合は、親のWidgetでScrollControllerを宣言して子のWidgetに渡すのがいいでしょう。
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _currentTab = 0;
final ScrollController _homeController = ScrollController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
_buildOffstage(0, Feed(_homeController)), ← 渡す
_buildOffstage(1, MyPage(_myPageController)), ← 渡す
],
),
bottomNavigationBar: FABBottomAppBar(
color: Colors.grey,
selectedColor: Colors.black,
onTabSelected: _selectedTab,
items: [
FABBottomAppBarItem(iconData: Icons.home, text: ""),
FABBottomAppBarItem(iconData: Icons.person_outline, text: ""),
],
)
);
}
Widget _buildOffstage(int index, Widget page) {
return Offstage(
offstage: index != _currentTab,
child: new TickerMode(
enabled: index == _currentTab,
child: page,
),
);
}
void _selectedTab(int index) {
if (_currentTab == index) {
if (index == 0) {
_homeController.animateTo(
0.0,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 300),
);
} else {
_myPageController.animateTo(
0.0,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 300),
);
}
} else {
setState(() {
_currentTab = index;
});
}
}
}
いいなと思ったら応援しよう!
投げ銭はいりません。それより無料でできる拡散をしてください!!
感想をツイートしていただけることが一番嬉しいです!!