Как сохранить состояния виджета во флаттера при навигации с помощью BottomNavigationBar?
В настоящее время я работаю над созданием приложения Flutter, которое будет сохранять состояния при переходе с одного экрана на другой и обратно при использовании BottomNavigationBar. Так же, как это работает в мобильном приложении Spotify; если вы перешли вниз до определенного уровня в иерархии навигации на одном из главных экранов, изменение экрана через нижнюю панель навигации, а затем возврат к старому экрану сохранят положение пользователя в этой иерархии, включая сохранение штат.
Я прислонилась головой к стене, безуспешно пробуя разные вещи.
Я хочу знать, как я могу запретить страницам в pageChooser()
, когда они переключаются, когда пользователь касается элемента BottomNavigationBar, восстанавливать себя и вместо этого сохранять состояние, в котором они уже находились (все страницы являются виджетами с состоянием).
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)
)
],
)
)
);
}
}
Ответы
Ответ 1
Используйте AutomaticKeepAliveClientMixin, чтобы запретить удаление содержимого вкладки.
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;
}
Чтобы убедиться, что ваша вкладка удаляется, когда ее не требуется сохранять, сделайте wantKeepAlive
возвращающей переменную класса. Вы должны позвонить в updateKeepAlive()
, чтобы обновить статус поддержки.
Пример с динамической поддержкой активности:
// 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();
}
}
Ответ 2
Вместо того, чтобы возвращать новый экземпляр каждый раз, когда вы запускаете pageChooser
, pageChooser
один экземпляр и верните его.
Пример:
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)
)
],
)
)
);
}
}
Или вы можете использовать такие виджеты, как PageView
или Stack
чтобы достичь того же.
Надеюсь, это поможет!
Ответ 3
Я нашел наиболее удобный способ сделать это - использовать виджет PageStorage вместе с PageStorageBucket, который действует как постоянный слой значения ключа.
Прочитайте эту статью для красивого объяснения → https://steemit.com/utopian-io/@tensor/persisting-user-interface-state-and-building-bottom-navigation-bars-in-dart-s-flutter -фреймворк