Я использую обычную нижнюю панель навигации с локальным состоянием, содержащим индекс текущей выбранной страницы. При нажатии на один из элементов навигации отображается постучанная страница:

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 представляет собой обзорный список, который содержит, помимо прочего, идентификатор элементов списка. Если вы нажмете на элемент в списке, он должен перейти на страницу сведений (3 в нижней панели навигации), где отображаются сведения о выбранном элементе и, следовательно, должен быть передан идентификатор выбранного элемента.

Navigator.of(context)... нельзя использовать, потому что отдельные страницы являются элементами навигационной панели и, следовательно, не являются маршрутами.

1
Martin Niederl 18 Апр 2019 в 11:54

2 ответа

Лучший ответ

Вам понадобится лучший способ управления государством. Я советую вам использовать шаблон 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();
}

Этот класс блока предоставляет поток вывода currentNavigationIndex. HomeScreen будет прослушивателем этого вывода, который предоставляет информацию о том, какой виджет должен быть создан и отображен в теле Scaffold виджета. Обратите внимание, что поток начинается с начального значения Navigation.TEXT.

Некоторые изменения необходимы в вашей домашней странице. Теперь мы используем виджет StreamBuilder для создания и предоставления виджета для свойства body. В некоторых словах StreamBuilder прослушивает поток, выводимый из блока, и когда принимаются некоторые данные, которые будут иметь значение 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();
  }
}

Поскольку вы хотите изменить виджет тела HomePage, когда нажимаете на определенные элементы, которые находятся в другом виджете, например, Overview, вам нужно передать блок этому новому виджету, а когда вы щелкаете по элементу, вы помещаете новые данные. в поток, что тело будет обновлено. Обратите внимание, что этот способ отправки экземпляра 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 не решат всех ваших задач. Ознакомьтесь с этой статьей один из лучших и больших, который говорит обо всем, что я написал здесь, с минимальными деталями.

Удачи!

1
Marcos Boaventura 19 Апр 2019 в 13:07

Внести некоторые изменения, как ..

  int _currentIndex = 0;

 void onTabTapped(int index) {
setState(() {
  _currentIndex = index;
});
 }


  body: _widgetOptions[_currentIndex],

Нажмите вкладку ..

onTap: onTabTapped,
0
Infusion Analysts 18 Апр 2019 в 09:18