Как перемещаться в нижней панели навигации с другой страницы? - PullRequest
1 голос
/ 18 апреля 2019

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

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

Ответы [ 2 ]

1 голос
/ 19 апреля 2019

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

Удачи!

0 голосов
/ 18 апреля 2019

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

  int _currentIndex = 0;

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


  body: _widgetOptions[_currentIndex],

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

onTap: onTabTapped,
...