我使用的是普通的底部导航栏,其局部状态包含当前所选页面的索引。点击导航项目之一时,将显示点击的页面:
class _HomePageState extends State<HomePage> {
int _selectedIndex = 1;
final _widgetOptions = [
Text('Index 0'),
Overview(),
Details(),
Text('Index 3'),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: _widgetOptions.elementAt(_selectedIndex),
bottomNavigationBar: BottomNavigationBar(
...
currentIndex: _selectedIndex,
onTap: onTap: (index) => _selectedIndex = index,
),
);
}
}
如果要从一页内导航到另一页并更新底部导航栏的选定索引,如何进行?
示例:第2页是概述列表,其中除其他外还包含列表项的ID。如果单击列表中的某个项目,则应将其导航到详细信息页面(底部导航栏中的3),以显示所选项目的详细信息,因此应传递所选项目的ID。
Navigator.of(context)...
无法使用,因为各个页面是导航栏的项目,因此不是路由。
答案 0 :(得分:1)
您将需要更好的状态管理方式。我建议您使用BLoC模式来管理此小部件中的导航更改。在这里,我将给出一个简化的示例,其中包含一些注释和对改进的外部引用。
// An enum to identify navigation index
enum Navigation { TEXT, OVERVIEW, DETAILS, OTHER_PAGE}
class NavigationBloc {
//BehaviorSubject is from rxdart package
final BehaviorSubject<Navigation> _navigationController
= BehaviorSubject.seeded(Navigation.TEXT);
// seeded with inital page value. I'am assuming PAGE_ONE value as initial page.
//exposing stream that notify us when navigation index has changed
Observable<Navigation> get currentNavigationIndex => _navigationController.stream;
// method to change your navigation index
// when we call this method it sends data to stream and his listener
// will be notified about it.
void changeNavigationIndex(final Navigation option) => _navigationController.sink.add(option);
void dispose() => _navigationController?.close();
}
此bloc类公开流输出currentNavigationIndex
。 HomeScreen
将是此输出的侦听器,该输出提供有关必须创建和显示在Scaffold
小部件主体上的小部件的信息。请注意,流以Navigation.TEXT
的初始值开始。
您的主页中需要进行一些更改。现在,我们使用StreamBuilder窗口小部件创建并提供body
属性的窗口小部件。简而言之,StreamBuilder正在侦听来自bloc的流,并且当接收到一些数据,这些数据将是Navigation
enum
值时,我们决定应在主体上显示什么小部件。
class _HomePageState extends State<HomePage> {
final NavigationBloc bloc = new NavigationBloc();
int _selectedIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<Navigation>(
stream: bloc.currentNavigationIndex,
builder: (context, snapshot){
_selectedIndex = snapshot.data.index;
switch(snapshot.data){
case Navigation.TEXT:
return Text('Index 0');
case Navigation.OVERVIEW:
// Here a thing... as you wanna change the page in another widget
// you pass the bloc to this new widget for it's capable to change
// navigation values as you desire.
return Overview(bloc: bloc);
//... other options bellow
case Navigation.DETAILS:
return Details(/* ... */);
}
},
),
bottomNavigationBar: BottomNavigationBar(
//...
currentIndex: _selectedIndex,
onTap: (index) => bloc.changeNavigationIndex(Navigation.values[index]),
),
);
}
@override
void dispose(){
bloc.dispose();// don't forgot this.
super.dispoe();
}
}
由于您要在单击其他小部件中的特定项目(例如Overview
)时更改HomePage的主体小部件,因此需要将整块传递给此新小部件,并且当您单击项目时,将新数据放入Stream中,以便刷新正文。请注意,这种将BLoC
实例发送到另一个小部件的方法不是更好的方法。我建议您看一下InheritedWidget
模式。为了避免写出更大的答案,我在这里做了一个简单的方法。
class Overview extends StatelessWidget {
final NavigationBloc bloc;
Overview({this.bloc});
@override
Widget build(BuildContext context) {
return YourWidgetsTree(
//...
// assuming that when you tap on an specific item yout go to Details page.
InSomeWidget(
onTap: () => bloc.changeNavigationIndex(Navigation.DETAILS);
),
);
}
}
我知道很多代码,这是执行此操作的一种复杂方法,但事实并非如此。 setState调用无法解决您的所有需求。看看这个article,这是最好的和更大的故事之一,它以最少的细节讨论了我在这里写的所有内容。
祝你好运!
答案 1 :(得分:0)
进行一些更改。.
int _currentIndex = 0;
void onTabTapped(int index) {
setState(() {
_currentIndex = index;
});
}
body: _widgetOptions[_currentIndex],
点击标签。
onTap: onTabTapped,
答案 2 :(得分:0)
您可以使用Provider来管理BottomNavigationBar的索引。 创建一个类来处理indexPage,并使用Consumer在小部件中使用它。不要忘记在
中注册ChangeNotifierProvider。ChangeNotifierProvider<NavigationModel> (create: (context) => NavigationModel(),),
class NavigationModel extends ChangeNotifier {
int _pageIndex = 0;
int get page => _pageIndex;
changePage(int i) {
_pageIndex = i;
notifyListeners();
}
}