切换拍子上的标签时,流未重新渲染

时间:2019-02-19 08:23:47

标签: dart flutter

我有一个流生成器,它显示来自服务器的“帖子”列表。我已经使用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(),
          ),
        ]));
  }
}

2 个答案:

答案 0 :(得分:1)

看看这段代码,我发表了一些评论。我可以使用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(); }
}

答案 1 :(得分:0)

我将PublishSubject更改为BehaviourSubject,它似乎可以正常工作。我也将它与Marcos Boaventura的答案结合使用。尽管我使用了两个流生成器。