Reputation: 23
I am learning Flutter and struggling with some state management issue.
I have a HomeScreen widget which contains Scaffold and a BottomNavigationBar. To switch pages based on the selected tab in BottomNavigationBar I am using PageView with PageController. Here is how the build
method of HomeScreen widget looks:
@override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: _currentIndex == 2,
appBar: AppBar(...properties),
body: PageView(
controller: _pageController,
children: _pages,
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[...items],
currentIndex: _currentIndex,
onTap: _onItemTapped, //This changes state _currentIndex and calls the method _pageController.jumpToPage(_currentIndex);
),
);
}
_currentIndex
initially is 0._pages
is a list containing 3 widgets._pageController
is simple PageController with initialPage set to 0.If you notice I am using a property extendBodyBehindAppBar: _currentIndex == 2
which is using _currentIndex
state and this is causing issue.
When I tap on the last Tab on the BottomNavigationBar the state the _currentIndex
changes to 2 and thus the extendBodyBehindAppBar
is set as true
which makes entire Scaffold rebuild itself and the state of the PageView is lost.
If comment out the line extendBodyBehindAppBar: _currentIndex == 2
, then even if the Scaffold rebuilds the state of the PageView widget is preserved.
As of my understanding the Flutter should keep the state of child Widgets even if the parent rebuilds because the WidgetTree is not changed or re-arranged. I tried using Key on PageView but nothing worked.
Any help is very much appreciated.
Upvotes: 2
Views: 563
Reputation: 564
refer to Lucas Salton Cardinali post on medium you need to use PageStorage to persit the state of the child you need after being destroyed.
here the example retrieved from the same page:
import 'package:flutter/material.dart';
// ...
void main() => runApp(MyApp());
// ...
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final List<Widget> pages = <Widget>[
ColorBoxPage(
key: PageStorageKey('pageOne'),
),
ColorBoxPage(
key: PageStorageKey('pageTwo'),
)
];
int currentTab = 0;
final PageStorageBucket _bucket = PageStorageBucket();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Persistence Example"),
),
body: PageStorage(
child: pages[currentTab],
bucket: _bucket,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: currentTab,
onTap: (int index) {
setState(() {
currentTab = index;
});
},
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'page 1',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'page2',
),
],
),
);
}
}
class ColorBoxPage extends StatelessWidget {
ColorBoxPage({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListView.builder(
itemExtent: 250.0,
itemBuilder: (context, index) => Container(
padding: EdgeInsets.all(10.0),
child: Material(
color: index % 2 == 0 ? Colors.cyan : Colors.deepOrange,
child: Center(
child: Text(index.toString()),
),
),
),
);
}
}
Upvotes: 1