dart - 在 flutter 上切换选项卡时不会重新渲染流

标签 dart flutter

我有一个流构建器,它显示来自服务器的“帖子”列表。我已经使用 BLoC 架构来实现这一点。 但出于某种原因,当我切换标签页并返回帖子消失时,如何防止帖子消失或让它们重新呈现?下面是我认为相关的一小部分代码我可以添加更多如果需要:

Tab 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"))));
            }
        }
      });
}

区 block 链:

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 模式来模拟 future 延迟的异步数据获取。此小部件可以正常工作,但您需要根据自己的需要进行调整。

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(); }
}

关于dart - 在 flutter 上切换选项卡时不会重新渲染流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54761678/

相关文章:

java - 如何为 Android 应用程序中的所有线程设置 uncaughtExceptionHandler?崩溃仅在某些情况下发生

dart - 如何使用构建器将 PageView 扩展到双方?

Dart 不会得到依赖

dart - 使用Null类型参数进行Dart 2.7的Dart迁移

regex - 如何将所有正则表达式匹配项放入字符串列表

rest - http GET 中的 ClientException "Invalid response reason phrase"

angular - Angular :无效参数: “…”的路由生成器未包含在传递的参数中

dart - 如何在Dart中创建静态扩展方法?

flutter - UI 崩溃堆栈跟踪中缺少原始文件

android-studio - 在flutter中查看小部件所有属性的快捷方式