Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Losing widget state when switching pages in a Flutter PageView

Tags:

flutter

I have a series of stateful widgets in a PageView managed by a PageController. I am using pageController.jumpToPage(index) to switch pages. When switching pages all state appears to be lost in the widget, as if it was recreated from scratch. I have tried using keepPage: true in the PageController but that doesn't seem to have any effect. Is this the intended behavior of a PageView or am I doing something wrong? Any suggestions appreciated, thanks!

like image 215
Matt Hall Avatar asked Aug 29 '17 17:08

Matt Hall


People also ask

What is Page snapping in flutter?

Snapping Page ScrollA plugin that acts similar to a PageView but either snaps to the closest page or scrolls multiple pages and then snaps, based on how fast the user scrolls.


2 Answers

use with AutomaticKeepAliveClientMixin to your SubPage.

then @override bool get wantKeepAlive => true; here is a sample

import 'package:flutter/material.dart';  void main() => runApp(new MyApp());  class MyApp extends StatelessWidget {   @override   Widget build(BuildContext context) {     return new MaterialApp(       title: 'Flutter Demo',       theme: new ThemeData(         primarySwatch: Colors.blue,       ),       home: new MyHomePage(title: 'Flutter Demo Home Page'),     );   } }  class MyHomePage extends StatefulWidget {   MyHomePage({Key key, this.title}) : super(key: key);    final String title;    @override   _MyHomePageState createState() => new _MyHomePageState(); }  class _MyHomePageState extends State<MyHomePage> {   @override   Widget build(BuildContext context) {     return DefaultTabController(       length: 4,       child: new Scaffold(         appBar: new AppBar(           bottom: new TabBar(             tabs: [               new Tab(icon: new Icon(Icons.directions_car)),               new Tab(icon: new Icon(Icons.directions_transit)),               new Tab(icon: new Icon(Icons.directions_bike)),               new Tab(                 icon: new Icon(Icons.airplanemode_active),               )             ],           ),         ),         body: new TabBarView(children: [           new OnePage(color: Colors.black,),           new OnePage(color: Colors.green,),           new OnePage(color: Colors.red,),           new OnePage(color: Colors.blue,),         ]),       ),     );   } }  class OnePage extends StatefulWidget {   final Color color;    const OnePage({Key key, this.color}) : super(key: key);    @override   _OnePageState createState() => new _OnePageState(); }  class _OnePageState extends State<OnePage> with AutomaticKeepAliveClientMixin<OnePage> {   @override   Widget build(BuildContext context) {     super.build(context);     return new SizedBox.expand(       child: new ListView.builder(         itemCount: 100,         itemBuilder: (context, index) {           return new Padding(             padding: const EdgeInsets.all(10.0),             child: new Text(               '$index',               style: new TextStyle(color: widget.color),             ),           );         },       ),     );   }    @override   bool get wantKeepAlive => true; } 
like image 81
JokerHYC Avatar answered Oct 07 '22 19:10

JokerHYC


keepPage: true is the default behavior; it means that the PageController will remember what page it's on if it is destroyed and recreated. This isn't what you want.

Instead, pass a page-specific PageStorageKey to the constructor of the pages. This helps Flutter give a unique storage bucket to your page. Then in your State that you want to have restored to its previous condition, you can use PageStorage.of(context) to get the storage bucket, which you can read values from in initState and write values to when they change. You can see an example in ExpansionTile.

like image 43
Collin Jackson Avatar answered Oct 07 '22 20:10

Collin Jackson