In the app, I am using PageView
as home and 3 pages in it - Profile, Console, Settings with AutomaticKeepAliveClientMixin
extension. In it, 2 of the pages(Profile and Console) have a 'Side Menu' screen using PageView
again.
The problem is that when I switch between home pages, I want that if the 'Side Menu' is open on any page, it(second PageView
) should jump to the initial page.
Here is the reduced version of the code-
Material app-
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Home();
);
}
}
Home Widget -
class Home extends StatefulWidget {
Home({Key key}) : super(key: key);
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _selectedIndex = 0;
final pageController = PageController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: pageController,
physics: PageScrollPhysics(
parent: ScrollPhysics(
parent: NeverScrollableScrollPhysics())),
children: <Widget>[
Tab1(),
Tab2(),
Tab3(),
],
),
//to set the bottom navigation bar and not reset the entire tree
bottomNavigationBar: StatefulBuilder(
builder: (BuildContext context, setState) {
return BottomNavigationBar(
currentIndex: _selectedIndex,
selectedItemColor: Colors.green[800],
onTap: (index) {
setState(() {
_selectedIndex = index;
});
pageController.jumpToPage(index);
},
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.person), label: 'Profile'),
BottomNavigationBarItem(
icon: Icon(Icons.connect_without_contact), label: 'Console'),
BottomNavigationBarItem(
icon: Icon(Icons.settings), label: 'Settings')
],
);
},
),
);
}
}
Same three pages -
class Tab1 extends StatefulWidget {
@override
_Tab1State createState() => _Tab1State();
}
class _Tab1State extends State<Tab1> with AutomaticKeepAliveClientMixin<Tab1> {
final controller = PageController();
//to use back button to go back to initial screen when poped
bool onWillPop() {
pageController.previousPage(
duration: Duration(milliseconds: 200),
curve: Curves.linear,
);
return false;
}
@override
get wantKeepAlive {
return true;
}
@override
Widget build(BuildContext context) {
super.build(context);
return PageView(
controller: controller,
children: [
Scaffold(
appBar:
AppBar(title: Text('Profile'), backgroundColor: Colors.grey[200]),
),
//so that back button brings user back to initial screen
WillPopScope(
onWillPop: () => Future.sync(onWillPop),
child: Scaffold(
appBar: AppBar(
title: Text('Side Menu Screen'),
),
),
)
],
);
}
}
class Tab2 extends StatefulWidget {
@override
_Tab2State createState() => _Tab2State();
}
class _Tab2State extends State<Tab2> with AutomaticKeepAliveClientMixin<Tab2> {
final controller = PageController();
//to use back button to go back to initial screen when poped
bool onWillPop() {
pageController.previousPage(
duration: Duration(milliseconds: 200),
curve: Curves.linear,
);
return false;
}
@override
get wantKeepAlive {
return true;
}
@override
Widget build(BuildContext context) {
super.build(context);
return PageView(
controller: controller,
children: [
Scaffold(
appBar:
AppBar(title: Text('Console'), backgroundColor: Colors.grey[200]),
),
//so that back button brings user back to initial screen
WillPopScope(
onWillPop: () => Future.sync(onWillPop),
child: Scaffold(
appBar: AppBar(
title: Text('Side Menu Screen'),
),
),
)
],
);
}
}
class Tab3 extends StatefulWidget {
@override
_Tab3State createState() => _Tab3State();
}
class _Tab3State extends State<Tab3> with AutomaticKeepAliveClientMixin<Tab3> {
final controller = PageController();
//to use back button to go back to initial screen when poped
bool onWillPop() {
pageController.previousPage(
duration: Duration(milliseconds: 200),
curve: Curves.linear,
);
return false;
}
@override
get wantKeepAlive {
return true;
}
@override
Widget build(BuildContext context) {
super.build(context);
return PageView(
controller: controller,
children: [
Scaffold(
appBar:
AppBar(title: Text('Settings'), backgroundColor: Colors.grey[200]),
),
//so that back button brings user back to initial screen
WillPopScope(
onWillPop: () => Future.sync(onWillPop),
child: Scaffold(
appBar: AppBar(
title: Text('Side Menu Screen'),
),
),
)
],
);
}
}
Possible ways-
- Detect when the tab or page goes off-screen and call the
controller.jumpToPage()
method. (best if possible)
Something like this-
@override
void dispose() {
if (controller.hasClients) {
controller.jumpToPage(controller.initialPage);
}
super.dispose();
}
- Listen to changes in the first
PageView
byonPageChanged
property. - Pop
willPopScope
after checking if its pushed.
Thanks for all your help...