如何在另一个页面的底部导航栏中导航?

时间:2019-04-18 08:54:51

标签: dart flutter navigation bottomnavigationview

我使用的是普通的底部导航栏,其局部状态包含当前所选页面的索引。点击导航项目之一时,将显示点击的页面:

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)...无法使用,因为各个页面是导航栏的项目,因此不是路由。

3 个答案:

答案 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类公开流输出currentNavigationIndexHomeScreen将是此输出的侦听器,该输出提供有关必须创建和显示在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();
  }
}