Reputation: 1609
Steps to reproduce: Swipe to the left, switch to the red Tab
and then switch to the purple Tab
again.
What is: After executing the steps to reproduce, the PageView
of the first Tab
is at the blue page again.
What should be: After executing the steps to reproduce, the PageView
of the first Tab
is still at the green page.
What am I missing here?
import "package:flutter/material.dart";
import "package:flutter/services.dart";
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
SystemChrome.setEnabledSystemUIOverlays([]);
return MaterialApp(
home: MyHome()
);
}
}
class MyHomeState extends State<MyHome> with TickerProviderStateMixin {
TabController tabController;
@override
void initState() {
tabController = tabController?? TabController(
vsync: this,
length: 2
);
super.initState();
}
@override
void dispose() {
tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
TabBar(
controller: tabController,
tabs: [
Container(
color: Colors.purple,
width: 100.0,
height: 50.0
),
Container(
color: Colors.pink,
width: 100.0,
height: 50.0
)
]
),
Expanded(
child: TabBarView(
controller: tabController,
children: [
MyPageView(),
MyPageView(),
],
)
)
]
)
);
}
}
class MyHome extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return MyHomeState();
}
}
class MyPageViewState extends State<MyPageView> {
PageController pageController;
@override
void initState() {
pageController = pageController?? PageController();
super.initState();
}
@override
void dispose() {
pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return PageView(
controller: pageController,
children: [
Container(
color: Colors.blue
),
Container(
color: Colors.green
)
]
);
}
}
class MyPageView extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return MyPageViewState();
}
}
Upvotes: 11
Views: 5807
Reputation: 1609
This is problem is solved with AutomaticKeepAliveClientMixin
. I used this before, but due to confusion on the wrong state. It obviously has to be mixed in with the class that contains the state you want to keep alive
.
Upvotes: 2
Reputation: 4098
I had this issue and found a much easier method to do this and that is to create a variable, say int index = 0
for example outside the statefulwidget class such that when that widget is created, there should be getters and setter before even creating the state, so when the class is called using the Navigator() the index of the page is unaltered. see example below
import 'package:flutter/material.dart';
int value = 0;
class MainpageScreen extends StatefulWidget {
static const routeName = '/main';
int getPage() {
return value;
}
void setPage(int page) {
value = page;
}
@override
_MainpageScreenState createState() => _MainpageScreenState();
}
class _MainpageScreenState extends State<MainpageScreen> {
PageController _pageController;
List<Widget> pages = [
//...
];
@override
void initState() {
_pageController = PageController(
keepPage: true,
initialPage: widget.getPage(),
);
super.initState();
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView.builder(
itemCount: 5,
onPageChanged: (index) => setState(() {
widget.setPage(index);
_pageController.animateToPage(index,
duration: Duration(milliseconds: 300), curve: Curves.ease);
}),
itemBuilder: (ctx, index) => pages[index],
controller: _pageController,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: widget.getPage(),
items: [
//...
],
onTap: (index) => setState(() {
widget.setPage(index);
_pageController.jumpToPage(index);
})),
);
}
}
Upvotes: 1