[英]how to make a bloc builder build a widget when its not on screen?
好的,所以我很難解釋,但我會盡力而為。 我正在嘗試制作一個遵循 Bloc state 管理的應用程序。 現在,我有一個 bloc class 控制底部導航欄和它顯示的小部件/片段,其中一個屏幕有一個列表視圖生成器,現在列表視圖的 state 也由一個 bloc 生成器管理。 列表的 bloc builder 負責顯示列表的加載 state(在開始時),而此列表視圖的 bloc class 負責通過與 API 處理程序通信從服務器獲取數據。 我的問題是,在加載數據時,如果用戶單擊底部導航欄以顯示另一個屏幕並返回到原始屏幕(具有列表視圖的屏幕),則數據永遠不會加載,列表視圖構建器也永遠不會創建列表項。
我想做的是當用戶點擊底部導航欄切換當前正在查看的小部件時,我希望加載數據並構建列表,即使選項卡/底部導航不是那個有清單
提要列表小部件 class
// ignore: must_be_immutable
class FeedList extends StatelessWidget {
final ScrollController _scrollController = new ScrollController();
final int _incrementValue = 5;
final FeedListBloc _feedListBloc = FeedListBloc();
int _start = 0;
int _end = 10;
bool fromHome;
int get start => _start;
int get end => _end;
List<Tournament> tournaments = new List<Tournament>();
FeedList({this.fromHome:false}) {
print("feed list constructor");
_feedListBloc.fetchTournaments(start, end, isHomeFeed: fromHome);
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_feedListBloc.fetchTournaments(start, end, isHomeFeed: true);
}
});
}
@override
Widget build(BuildContext context) {
return BlocListener(
bloc: _feedListBloc,
listener: (context, FeedListState state) {
if (state is ErrorState)
Scaffold.of(context).showSnackBar(SnackBar(
action: SnackBarAction(
textColor: Theme.of(context).accentColor,
label: "dismiss",
onPressed: () {
Scaffold.of(context).hideCurrentSnackBar();
},
),
duration: Duration(seconds: 3),
content: Text(
state.errorMSG,
style:
Theme.of(context).textTheme.headline1.copyWith(fontSize: 12),
),
elevation: 0,
backgroundColor: Color(0xff363636),
behavior: SnackBarBehavior.floating,
));
else if (state is DataLoadedState) {
if (state.tournaments.length > 0) {
_incrementStartEnd();
tournaments.addAll(state.tournaments);
}
}
},
child: BlocBuilder(
bloc: _feedListBloc,
builder: (context, FeedListState state) {
if (state is ShimmerState) {
return ListView.builder(
itemCount: 3,
itemBuilder: (context, index) => Shimmer.fromColors(
child: FeedListItem(null),
baseColor: Color(0xFF1D1D1D),
highlightColor: Color(0xff202020)));
} else {
return RefreshIndicator(
onRefresh: () async {
await refreshFeed();
},
child: ListView.builder(
physics: AlwaysScrollableScrollPhysics(),
controller: _scrollController,
itemCount: tournaments.length + 1,
itemBuilder: (context, index) => _getListItems(context, index),
),
);
}
},
),
);
}
_getListItems(BuildContext context, int index) {
if (index >= tournaments.length && tournaments.isNotEmpty)
return Padding(
padding: const EdgeInsets.only(bottom: 35),
child: Center(child: CircularProgressIndicator()),
);
else if (index == tournaments.length - 1)
return Padding(
padding: const EdgeInsets.only(bottom: 30),
child: FeedListItem(tournaments[index]),
);
else if (tournaments.isNotEmpty) return FeedListItem(tournaments[index]);
}
void dispose() {
_feedListBloc.close();
}
void _incrementStartEnd() {
print("incremented");
_start = _end;
_end += _incrementValue;
}
refreshFeed() async {
tournaments.clear();
_start = 0;
_end = 10;
await _feedListBloc.fetchTournaments(start, end, isHomeFeed: fromHome);
}
}
提要列表塊 class
class FeedListBloc extends Bloc<FeedListEvent, FeedListState> {
Future<void> fetchTournaments(int start, int end,
{bool isHomeFeed: false}) async {
await Future.delayed(Duration(seconds: 3));
dynamic reply =
await API.getHomeFeedTournaments(start, end, isHomeFeed: isHomeFeed);
if (reply == null)
this.add(ErrorEvent("could not load "));
else if (reply is String)
this.add(ErrorEvent(reply));
else
this.add(DataLoadedEvent(reply as List<Tournament>));
}
@override
FeedListState get initialState => FeedListState.initState();
@override
Stream<FeedListState> mapEventToState(FeedListEvent event) async* {
if (event is ErrorEvent)
yield FeedListState.errorState(event.errorMsg);
else if (event is DataLoadedEvent)
yield FeedListState.dataLoaded(event.tournaments);
}
}
請告訴我我正在嘗試做的事情是否有誤,或者是否有更好的方法。 本質上我是這樣做的,因為我不希望每次用戶切換屏幕時都進行 API 調用,但我確實希望即使用戶切換屏幕也能構建列表, 3 秒延遲在 bloc 中獲取更多方法是讓我了解到底發生了什么
好吧,這對我來說有點難以解釋,但我會盡力而為。 我正在嘗試制作一個遵循 Bloc state 管理的應用程序。 現在,我有一個塊 class 控制底部導航欄和它顯示的小部件/片段,其中一個屏幕有一個列表視圖構建器,現在列表視圖的 state 也由一個塊構建器管理。 列表的 bloc builder 負責顯示列表的加載 state(在開頭),而此列表視圖的 bloc class 負責通過與 ZDB974238714CA8DE634A7CED1 通信從服務器獲取數據。 我的問題是,當數據正在加載時,如果用戶單擊底部導航欄以顯示另一個屏幕並返回到原始屏幕(具有列表視圖的屏幕),那么數據永遠不會被加載並且列表視圖構建器永遠不會創建列表項。
我想要做的是當用戶單擊底部導航欄以切換正在查看的當前小部件時,我希望加載數據並構建列表,即使選項卡/底部導航不是有清單
提要列表小部件 class
// ignore: must_be_immutable
class FeedList extends StatelessWidget {
final ScrollController _scrollController = new ScrollController();
final int _incrementValue = 5;
final FeedListBloc _feedListBloc = FeedListBloc();
int _start = 0;
int _end = 10;
bool fromHome;
int get start => _start;
int get end => _end;
List<Tournament> tournaments = new List<Tournament>();
FeedList({this.fromHome:false}) {
print("feed list constructor");
_feedListBloc.fetchTournaments(start, end, isHomeFeed: fromHome);
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_feedListBloc.fetchTournaments(start, end, isHomeFeed: true);
}
});
}
@override
Widget build(BuildContext context) {
return BlocListener(
bloc: _feedListBloc,
listener: (context, FeedListState state) {
if (state is ErrorState)
Scaffold.of(context).showSnackBar(SnackBar(
action: SnackBarAction(
textColor: Theme.of(context).accentColor,
label: "dismiss",
onPressed: () {
Scaffold.of(context).hideCurrentSnackBar();
},
),
duration: Duration(seconds: 3),
content: Text(
state.errorMSG,
style:
Theme.of(context).textTheme.headline1.copyWith(fontSize: 12),
),
elevation: 0,
backgroundColor: Color(0xff363636),
behavior: SnackBarBehavior.floating,
));
else if (state is DataLoadedState) {
if (state.tournaments.length > 0) {
_incrementStartEnd();
tournaments.addAll(state.tournaments);
}
}
},
child: BlocBuilder(
bloc: _feedListBloc,
builder: (context, FeedListState state) {
if (state is ShimmerState) {
return ListView.builder(
itemCount: 3,
itemBuilder: (context, index) => Shimmer.fromColors(
child: FeedListItem(null),
baseColor: Color(0xFF1D1D1D),
highlightColor: Color(0xff202020)));
} else {
return RefreshIndicator(
onRefresh: () async {
await refreshFeed();
},
child: ListView.builder(
physics: AlwaysScrollableScrollPhysics(),
controller: _scrollController,
itemCount: tournaments.length + 1,
itemBuilder: (context, index) => _getListItems(context, index),
),
);
}
},
),
);
}
_getListItems(BuildContext context, int index) {
if (index >= tournaments.length && tournaments.isNotEmpty)
return Padding(
padding: const EdgeInsets.only(bottom: 35),
child: Center(child: CircularProgressIndicator()),
);
else if (index == tournaments.length - 1)
return Padding(
padding: const EdgeInsets.only(bottom: 30),
child: FeedListItem(tournaments[index]),
);
else if (tournaments.isNotEmpty) return FeedListItem(tournaments[index]);
}
void dispose() {
_feedListBloc.close();
}
void _incrementStartEnd() {
print("incremented");
_start = _end;
_end += _incrementValue;
}
refreshFeed() async {
tournaments.clear();
_start = 0;
_end = 10;
await _feedListBloc.fetchTournaments(start, end, isHomeFeed: fromHome);
}
}
飼料清單集團 class
class FeedListBloc extends Bloc<FeedListEvent, FeedListState> {
Future<void> fetchTournaments(int start, int end,
{bool isHomeFeed: false}) async {
await Future.delayed(Duration(seconds: 3));
dynamic reply =
await API.getHomeFeedTournaments(start, end, isHomeFeed: isHomeFeed);
if (reply == null)
this.add(ErrorEvent("could not load "));
else if (reply is String)
this.add(ErrorEvent(reply));
else
this.add(DataLoadedEvent(reply as List<Tournament>));
}
@override
FeedListState get initialState => FeedListState.initState();
@override
Stream<FeedListState> mapEventToState(FeedListEvent event) async* {
if (event is ErrorEvent)
yield FeedListState.errorState(event.errorMsg);
else if (event is DataLoadedEvent)
yield FeedListState.dataLoaded(event.tournaments);
}
}
請告訴我我正在嘗試做的事情是否錯誤,或者是否有更好的方法。 基本上我這樣做是因為我不希望在每次用戶切換屏幕時都進行 API 調用,但我確實希望即使用戶切換屏幕也能構建列表,該塊中的 3 秒延遲獲取更多方法是讓我了解到底發生了什么
如果您只是嘗試使用flutter_bloc
更新小部件上顯示的數據,則可以使用BlocListener或BlocBuilder 。 一旦根據您的操作更新了 Bloc,就可以在這些小部件內處理數據更改。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.