У меня есть домашняя страница с tabBarView
с 2 страницами, дом и избранное.На домашней странице есть gridview
, чьи ячейки заполнены streambuilder
.При нажатии они используют Навигатор для перенаправления на страницу сведений для этой ячейки.Я могу вкладывать между 2 вкладками.После перехода на страницу сведений (с домашней страницы) и возвращения домой gridView
правильно отображает свои данные.Но после этого, если я перейду на страницу избранного и вернусь домой, данные gridView
будут потеряны.
Я попытался AutomaticKeepAliveClientMixin
и wantKeepAlive = true
, как рекомендуется для SO.
Виджет домашней страницы не перестраивается при переходе между закладками и избранными, в соответствии с отладчиком, и данные отображаются нормально.
Переход со страницы сведений на домашнюю страницу перестраивает домашнюю страницустраница, и это тоже хорошо, как данные отображаются.Только если после этого я перейду на вкладку «Избранное» и вернусь снова, проблема возникнет.
Я использую шаблон блока и имею ссылку на блок провайдера в домашнем виджете.Он передает это в gridView
.
Я использую стандартные tabBarView и Navigator в SliverAppBar.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MovieProvider(
euCollBloc: EuThemeCollectionBloc(API()),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(),
home: MyHomePage(),
),
);
}
}
body: TabBarView(
children: <Widget>[
PageOne(),
PageTwo(),
],
bottom: TabBar(
tabs: <Widget>[
Tab(
text: "Home",
icon: Icon(Icons.home),
),
Tab(
text: "Favorites",
icon: Icon(Icons.favorite),
),
],
controller: _tabController,
))
.......
Навигатор, используемый в виджете PageOne:
.......
return GridView.builder(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: snapshot.data.length,
itemBuilder: (context, index) => GestureDetector(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => EuroCard(
preview: snapshot.data[index].preview ?? "",
title: snapshot.data[index].title,
description: snapshot.data[index].description,
),
));
},
child: Card(
.......
Использование (возможно, слишком продвинутого для меня) провайдера и блочного кода из учебника по тензору на YouTube.
Блок:
class EuThemeCollectionBloc {
final API api;
Stream<List<EuThemeCollection>> _results = Stream.empty();
Stream<String> _log = Stream.empty();
ReplaySubject<String> _query = ReplaySubject<String>();
Stream<String> get log => _log;
Stream<List<EuThemeCollection>> get results => _results;
Sink<String> get query => _query;
EuThemeCollectionBloc(this.api) {
_results = _query.distinct().asyncMap(api.get).asBroadcastStream();
_log = Observable(results)
.withLatestFrom(_query.stream, (_, query) => 'Results for $query')
.asBroadcastStream();
}
void dispose() {
_query.close();
}
}
провайдер:
class MovieProvider extends InheritedWidget {
final EuThemeCollectionBloc euCollBloc;
@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
static EuThemeCollectionBloc of(BuildContext context) =>
(context.inheritFromWidgetOfExactType(MovieProvider) as MovieProvider)
.euCollBloc;
MovieProvider({Key key, EuThemeCollectionBloc euCollBloc, Widget child})
: this.euCollBloc = euCollBloc ?? EuThemeCollectionBloc(API()),
super(child: child, key: key);
}
Я пытался использовать BehaviorSubject, но затем я получаю ошибку во время выполнения, ссылаясь на поток запросов в mainстраница:
Ошибка: получатель 'euCollBloc' не определен для класса 'EuroCard'.- «EuroCard» из пакета «bloc_example / euroCard.dart» («lib / euroCard.dart»).Попробуйте исправить имя с именем существующего получателя или определить получатель или поле с именем 'euCollBloc'.
ИСПРАВЛЕНО: Мне нужно было добавить super.build (context) к виджету PageOne (GridView) - itрасширяет состояние с помощью AutomaticKeepAliveClientMixin, поэтому его необходимо переопределить.Извините, изначально даже не публиковал раздел о виновниках.
class _PageOneState extends State<PageOne> with
AutomaticKeepAliveClientMixin<PageOne>{
@override
bool get wantKeepAlive => true;
Widget build(BuildContext context){
super.build(context);
var euCollBloc = MovieProvider.of(context);