我有一个流生成器,显示来自服务器的“帖子”列表。我已经使用BLoC架构来完成此任务。 但是由于某些原因,当我切换标签并返回时,帖子消失了,如何防止帖子消失或重新渲染? 以下是我的代码的一小部分,我认为是相关的,如果需要可以添加更多代码:
标签UI(并非所有代码,包含BLoC的文件都在顶部导入):
@override
void initState() {
bloc.fetchMyPosts();
super.initState();
}
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: Text("Posts", style: Style.appBarStyle),
bottom: TabBar(
tabs: [
Tab(
text: "My Posts",
),
Tab(
text: "My Other Posts",
),
],
),
),
body: TabBarView(
children: [
Posts(stream: bloc.myPosts), //Stream builder with SliverChildBuilderDelegate
Posts(stream:bloc.myOtherPosts),//Stream builder with SliverChildBuilderDelegate
],
),
),
);
}
流构建器(帖子):
Widget Posts({Stream stream, //Other variables}) {
return StreamBuilder(
stream:stream,
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch(snapshot.connectionState) {
case ConnectionState.none:
return Row(
children: <Widget>[
Flexible(
child: Text("Please check if you are connected to the internet"),
),
],
);
break;
case ConnectionState.waiting:
if (snapshot.data == null){
return Container(
color: Color(0xFFF4F4FF),
child: Container(child:Center(child:Text(variable?"Text one":"Text two"))));
} else return Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: CircularProgressIndicator(),
),
Center(
child: Text("Loading"),
),
],
);
break;
case ConnectionState.active:
case ConnectionState.done:
if (snapshot.hasData) {
return Container(
color:Colors.white,
child: CustomScrollView(
scrollDirection: Axis.vertical,
shrinkWrap: false,
slivers: <Widget>[
SliverPadding(
padding: const EdgeInsets.symmetric(vertical: 24.0),
sliver: SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => PostCard(post:snapshot.data[index],//variables),
childCount: snapshot.data.length,
),
),
)
],
));
}
if (snapshot.data == null){
return Container(
color: Color(0xFFF4F4FF),
child: Container(child:Center(child:Text(variable?"Text one":"Text two"))));
}
}
});
}
BLoC:
class Bloc{
ApiClient _client = ApiClient();
final _myPosts = BehaviourSubject<List<Post>>();
final _myOtherPosts = BehaviourSubject<List<Post>>();
Stream<List<Post>> get myPosts => _myPosts.stream;
Stream<List<Post>> get myOtherPosts => _myOtherPosts.stream;
fetchMyPosts() async {
List<Post> posts = await _client.getMyPosts();
_myPosts.sink.add(posts);
}
fetchMyOtherPosts() async {
List<Post> posts = await _client.getMyOtherPosts();
_myOtherPosts.sink.add(posts);
}
dispose(){
_myPosts.close();
_myOtherPosts.close();
}
}
final bloc = Bloc();
主屏幕:
class MainScreen extends StatefulWidget {
UserBloc userBloc;
MainScreen({this.userBloc});
@override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
int _currentIndex = 0;
onTabTapped(int index) {
setState(() {
_currentIndex = index;
});
}
Widget getPage(int index) {
if (index == 0) {
return PostPage(myHandle: widget.userBloc.userValue);
}
if (index == 1) {
return PageOne();
}
if (index == 3) {
return PageTwo();
}
if (index == 4) {
return PageThree(userBloc: widget.userBloc);
}
return PostPage(userBloc: widget.userBloc);
}
Widget customNav() {
return Container(
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
icon: Icon(Icons.library_books),
onPressed: () => setState(() {
_currentIndex = 0;
})),
// MORE ICONS but similar code
],
));
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(children: <Widget>[
getPage(_currentIndex),
Positioned(
bottom: 0.0,
left: 0.0,
right: 0.0,
child: customNav(),
),
]));
}
}
最佳答案
看看这段代码,我发表了一些评论。我可以使用streambuilder和bloc模式来执行此操作,以模拟异步数据获取,并延迟将来的时间。该小部件正在运行,但是您需要适应您的需求。
class TabWidget extends StatefulWidget {
@override
_TabWidgetState createState() => _TabWidgetState();
}
class _TabWidgetState extends State<TabWidget> with SingleTickerProviderStateMixin {
Bloc _bloc;
@override
void initState() {
super.initState();
_bloc = Bloc(); // can be your bloc.fetchData();
}
@override
void dispose() {
_bloc?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
//i really recomment using stream builder to create all layout
// if length property is dynamic
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: Text("Tab screen"),
bottom: TabBar(
tabs: [
Tab( text: "My Posts" ),
Tab( text: "Other" ),
],
),
),
body: StreamBuilder<List<Widget>>(
stream: _bloc.getTabData,
builder: (context, asyncSnapshot){
switch(asyncSnapshot.connectionState){
case ConnectionState.none:
return Row(
children: <Widget>[
Flexible(
child: Text("handle none state here, this is because i am simulate a async event"),
),
],
);
break;
case ConnectionState.waiting:
return Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: CircularProgressIndicator(),
),
Center(
child: Text("Loading data..."),
),
],
);
break;
case ConnectionState.active:
case ConnectionState.done:
//assuming that snapshot has valid data...
return TabBarView(
children:[
asyncSnapshot.data[0],
asyncSnapshot.data[1],
],
);
}
}
),
),
);
}
}
class Bloc{
// post items
// just to simulate data
List<Widget> _tabList1 = List.generate(10, (index){ return Text("TAB 1 Item $index");} );
List<Widget> _tabList2 = List.generate(10, (index){ return Text("TAB 2 Item $index");} );
//tab's data stream
PublishSubject< List<Widget>> _tabData = PublishSubject();
Observable<List<Widget>> get getTabData => _tabData.stream;
Bloc() {
Future.delayed(Duration(seconds: 5), () {
List<Widget> tabDataWidgets = List();
// adding tab's data
tabDataWidgets.add( ListView(
children: _tabList1,
) );
tabDataWidgets.add( ListView(
children: _tabList2,
) );
_addingToSink( tabDataWidgets );
});
}
void _addingToSink( final List<Widget> list) => _tabData.sink.add( list );
dispose(){ _tabData?.close(); }
}