Je travaille actuellement à la création d'une application Flutter qui préservera les états lors du passage d'un écran à un autre et inversement lors de l'utilisation de BottomNavigationBar . Tout comme cela fonctionne dans l'application mobile Spotify; Si vous avez atteint un certain niveau dans la hiérarchie de navigation sur l’un des écrans principaux, le changement d’écran via la barre de navigation inférieure, puis le retour à l’ancien écran, conserveront la position de l’utilisateur dans cette hiérarchie, notamment l'état.
J'ai couru ma tête contre le mur, essayant diverses choses sans succès.
Je veux savoir comment je peux empêcher les pages dans pageChooser()
, lorsqu'elles sont basculées une fois que l'utilisateur appuie sur l'élément BottomNavigationBar, de se reconstruire et de conserver l'état dans lequel il se trouvait déjà (les pages sont toutes des widgets avec état).
import 'package:flutter/material.Dart';
import './page_plan.Dart';
import './page_profile.Dart';
import './page_startup_namer.Dart';
void main() => runApp(new Recipher());
class Recipher extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Pages();
}
}
class Pages extends StatefulWidget {
@override
createState() => new PagesState();
}
class PagesState extends State<Pages> {
int pageIndex = 0;
pageChooser() {
switch (this.pageIndex) {
case 0:
return new ProfilePage();
break;
case 1:
return new PlanPage();
break;
case 2:
return new StartUpNamerPage();
break;
default:
return new Container(
child: new Center(
child: new Text(
'No page found by page chooser.',
style: new TextStyle(fontSize: 30.0)
)
),
);
}
}
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
body: pageChooser(),
bottomNavigationBar: new BottomNavigationBar(
currentIndex: pageIndex,
onTap: (int tappedIndex) { //Toggle pageChooser and rebuild state with the index that was tapped in bottom navbar
setState(
(){ this.pageIndex = tappedIndex; }
);
},
items: <BottomNavigationBarItem>[
new BottomNavigationBarItem(
title: new Text('Profile'),
icon: new Icon(Icons.account_box)
),
new BottomNavigationBarItem(
title: new Text('Plan'),
icon: new Icon(Icons.calendar_today)
),
new BottomNavigationBarItem(
title: new Text('Startup'),
icon: new Icon(Icons.alarm_on)
)
],
)
)
);
}
}
Utilisez AutomaticKeepAliveClientMixin pour forcer le contenu de votre onglet à ne pas être supprimé.
class PersistantTab extends StatefulWidget {
@override
_PersistantTabState createState() => _PersistantTabState();
}
class _PersistantTabState extends State<PersistantTab> with AutomaticKeepAliveClientMixin {
@override
Widget build(BuildContext context) {
return Container();
}
// Setting to true will force the tab to never be disposed. This could be dangerous.
@override
bool get wantKeepAlive => true;
}
Pour vous assurer que votre onglet est éliminé lorsqu'il n'est pas nécessaire de le conserver, faites en sorte que wantKeepAlive
renvoie une variable de classe. Vous devez appeler updateKeepAlive()
pour mettre à jour le statut Keep Alive.
Exemple avec dynamique Keep Alive:
// class PersistantTab extends StatefulWidget ...
class _PersistantTabState extends State<PersistantTab>
with AutomaticKeepAliveClientMixin {
bool keepAlive = false;
@override
void initState() {
doAsyncStuff();
}
Future doAsyncStuff() async {
keepAlive = true;
updateKeepAlive();
// Keeping alive...
await Future.delayed(Duration(seconds: 10));
keepAlive = false;
updateKeepAlive();
// Can be disposed whenever now.
}
@override
bool get wantKeepAlive => keepAlive;
@override
Widget build(BuildContext context) {
return Container();
}
}
Au lieu de renvoyer une nouvelle instance chaque fois que vous exécutez pageChooser
, faites-en créer une et renvoyez la même.
Exemple:
class Pages extends StatefulWidget {
@override
createState() => new PagesState();
}
class PagesState extends State<Pages> {
int pageIndex = 0;
// Create all the pages once and return same instance when required
final ProfilePage _profilePage = new ProfilePage();
final PlanPage _planPage = new PlanPage();
final StartUpNamerPage _startUpNamerPage = new StartUpNamerPage();
Widget pageChooser() {
switch (this.pageIndex) {
case 0:
return _profilePage;
break;
case 1:
return _planPage;
break;
case 2:
return _startUpNamerPage;
break;
default:
return new Container(
child: new Center(
child: new Text(
'No page found by page chooser.',
style: new TextStyle(fontSize: 30.0)
)
),
);
}
}
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
body: pageChooser(),
bottomNavigationBar: new BottomNavigationBar(
currentIndex: pageIndex,
onTap: (int tappedIndex) { //Toggle pageChooser and rebuild state with the index that was tapped in bottom navbar
setState(
(){ this.pageIndex = tappedIndex; }
);
},
items: <BottomNavigationBarItem>[
new BottomNavigationBarItem(
title: new Text('Profile'),
icon: new Icon(Icons.account_box)
),
new BottomNavigationBarItem(
title: new Text('Plan'),
icon: new Icon(Icons.calendar_today)
),
new BottomNavigationBarItem(
title: new Text('Startup'),
icon: new Icon(Icons.alarm_on)
)
],
)
)
);
}
}
Ou vous pouvez utiliser des widgets tels que PageView
ou Stack
pour obtenir le même résultat.
J'espère que cela pourra aider!