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