Flutter切换到Tab重新加载小部件并运行FutureBuilder

Kho*_*Phi 26 dart flutter

问题:

我有2个选项卡使用Default Tabs Controller,如下所示:

Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        drawer: Menu(),
        appBar: AppBar(
          title: Container(
            child: Text('Dashboard'),
          ),
          bottom: TabBar(
            tabs: <Widget>[
              Container(
                padding: EdgeInsets.all(8.0),
                child: Text('Deals'),
              ),
              Container(
                padding: EdgeInsets.all(8.0),
                child: Text('Viewer'),
              ),
            ],
          ),
        ),
        body: TabBarView(
          children: <Widget>[
            DealList(),
            ViewersPage(),
          ],
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

DealList()是一个StatefulWidget像这样建立的:

Widget build(BuildContext context) {
    return FutureBuilder(
      future: this.loadDeals(),
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        print('Has error: ${snapshot.hasError}');
        print('Has data: ${snapshot.hasData}');
        print('Snapshot data: ${snapshot.data}');
        return snapshot.connectionState == ConnectionState.done
            ? RefreshIndicator(
                onRefresh: showSomething,
                child: ListView.builder(
                  physics: const AlwaysScrollableScrollPhysics(),
                  itemCount: snapshot.data['deals'].length,
                  itemBuilder: (context, index) {
                    final Map deal = snapshot.data['deals'][index];
                    print('A Deal: ${deal}');
                    return _getDealItem(deal, context);
                  },
                ),
              )
            : Center(
                child: CircularProgressIndicator(),
              );
      },
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

有了上面的内容,每当我切换回DealList()选项卡时会发生什么:它重新加载.

扑

有没有办法在完成一次后阻止重新运行FutureBuilder?(计划是让用户使用RefreshIndicator重新加载.所以更改选项卡不应该触发任何内容,除非用户明确这样做.)

Jon*_*ams 56

这里有两个问题,第一个:

TabController切换选项卡时,它会卸载旧的小部件树以节省内存.如果要更改此行为,则需要混合AutomaticKeepAliveClientMixin到选项卡窗口小部件的状态.

class _DealListState extends State<DealList> with AutomaticKeepAliveClientMixin<DealList> {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context); // need to call super method.
    return /* ... */
  }
}
Run Code Online (Sandbox Code Playgroud)

第二个问题是你使用的FutureBuilder- 如果你提供一个新FutureFutureBuilder,它不能告诉结果将与上次相同,所以它必须重建.(请记住,Flutter可能会将您的构建方法调用到一帧一次).

return FutureBuilder(
  future: this.loadDeals(), // Creates a new future on every build invocation.
  /* ... */
);
Run Code Online (Sandbox Code Playgroud)

相反,您希望将未来分配给initState中State类的成员,然后将此值传递给FutureBuilder.确保后续重建的未来是相同的.如果要强制State重新加载交易,您始终可以创建一个重新分配_loadingDeals成员和调用的方法setState.

Future<...> _loadingDeals;

@override
void initState() {
  _loadingDeals = loadDeals(); // only create the future once.
  super.initState();
}

@override
Widget build(BuildContext context) {
  super.build(context); // because we use the keep alive mixin.
  return new FutureBuilder(future: _loadingDeals, /* ... */);
}
Run Code Online (Sandbox Code Playgroud)

  • 我尝试在我的应用程序中实现此功能,具有“bottomNavigationBar”,但每当我更改页面时,它仍然会触发 API。 (10认同)
  • 有没有initState的解决方案?因为我正在使用带有bloc模式的streamBuilder.所有数据获取逻辑都在我的bloc类中. (4认同)
  • 他们至少可以提供一种方法来真正防止选项卡被重建。该解决方案仍然重建小部件,但仅运行 future 一次。 (4认同)
  • 事实上,你用一颗石头解决了我的两个问题。非常感谢。就像解决方案一样,真的很重要,而且解释也很有意义。现在工作。 (2认同)