数据更新后颤振列表视图不更新

Posted

技术标签:

【中文标题】数据更新后颤振列表视图不更新【英文标题】:Flutter listview not updating after data update 【发布时间】:2020-06-03 21:19:13 【问题描述】:

我在 bottomSheet 中有一个 ListView,它是使用元素数组构建的。目前我在那里有一个“空”项目,然后是.clear()ed,并在异步数据库调用后填充。

变量更新是正确的,我尝试使用setState(()),但 ListView 根本没有更新。我需要关闭 bottomSheet,重新打开它,然后 ListView 就会有正确的项目。

我只需要致电setState 还是需要标记bottomSheet 构建器才能更新?

主 ListView 部分:

 @override
  Widget build(BuildContext context) 
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('My Map'),
          backgroundColor: Colors.green[700],
        ),

        //Put in a stack widget so can layer other widgets on top of map widget
        body: Stack(
          children: <Widget>[
            GoogleMap(
              mapType: _currentMapType,
              markers: _markers,
              onMapCreated: _onMapCreated,
              onCameraMove: _onCameraMove,
              initialCameraPosition: CameraPosition(
                target: _center,
                zoom: 11.0,
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: Align(
                  alignment: Alignment.bottomCenter,
                  child: Row(mainAxisSize: MainAxisSize.min, children: <Widget>[
                    SizedBox(width: 16.0),

                    Builder(
                      builder: (context) => FloatingActionButton(   
                          ...
                      ),

                    ),

                    SizedBox(width: 16.0),

                    FloatingActionButton(
                      ...
                    ),

                    SizedBox(width: 16.0),

                    Builder(
                      builder: (context) => FloatingActionButton(
                          child: Icon(Icons.file_download, size: 36.0),
                          backgroundColor: Colors.green,
                          onPressed: () 
                            showBottomSheet(
                                context: context,
                                builder: (context) 
                                  return ListView(
                                    padding: EdgeInsets.all(15.0),
                                    children: <Widget>[

                                         ...

                                      Divider(),

                                      ListTile(
                                        title: Text("Remote JSON Download"),
                                        trailing:
                                        Icon(Icons.refresh),
                                        selected: true,
                                        onTap: _OnPressedReloadJSON,               <-------------
                                      ),

                                      Divider(),

                                      Container(
                                        height: 150.0,
                                        child: ListView.builder(               <-------------
                                          scrollDirection: Axis.horizontal,

                                          itemCount : testList.length, 
                                          itemBuilder: (BuildContext context, int index) 
                                              return Container(
                                                padding: EdgeInsets.all(5.0),
                                                margin: EdgeInsets.all(5.0),
                                                width: 150.0,
                                                color: Colors.red,
                                                child: Text(testList[index]),
                                              );
                                          ,

                                        ),
                                      ),

异步获取:

class _MyAppState extends State<MyApp> 

  ...

  _OnPressedReloadJSON() 
    fetchJSONAndMakeListTile();
  

  ...

  List<String> testList= ["empty"];

  Future<http.Response> fetchJSONAndMakeListTile() async 
    final response = await http.get('https://..... file.json');

    // If the server did return a 200 OK response, then parse the JSON.
    if (response.statusCode == 200) 
      List<db_manager.MyObject> myObjects = (json.decode(response.body) as List)
          .map((e) => db_manager.MyObject.fromJson(e))
          .toList();

      testList.clear();
      myObjects.forEach((db_manager.MyObject al) 
        testList.add(al.code);
        print("debug:"+al.code+" - "+al.name);        <------------- prints correctly
      );

      //TODO Does this even work?
      //Trigger update of state - ie redraw/reload UI elements
      setState(() );

     else 
      // If the server did not return a 200 OK response, then throw an exception.
      print(response);
      throw Exception('Failed to load json');
    
  

更新:

我已将 BottomSheet 构建器抽象为另一个类(根据另一个答案)作为它自己的 StatefulWidget,但我似乎无法从我的主 dart 文件中访问 void onPress() 方法。如果 BottomSheet 创建/构建器在这个单独的 dart 文件中,我如何调用它来构建,然后使用 async 调用更新列表视图内容列表来更新其状态?

BottomSheetWidget.dart

class BottomSheetDatabases extends StatefulWidget 
  @override
  _BottomSheetDatabases createState() => _BottomSheetDatabases();


class _BottomSheetDatabases extends State<BottomSheetDatabases> 

  void _onpress() 

  

  void loadMe() 

  

  List<String> testList= ["empty"];

  @override
  Widget build(BuildContext context) 
    return BottomSheet(

        builder: (context) 
          return ListView(
            padding: EdgeInsets.all(15.0),
            children: <Widget>[
              ListTile(
                ...

              ),

              Divider(),

              Container(
                height: 150.0,
                child: ListView.builder(
                  scrollDirection: Axis.horizontal,

                  itemCount: testList.length,
                  itemBuilder: (BuildContext context, int index) 
                    return Container(
                      key: UniqueKey(),
                      //TODO  ??
                      padding: EdgeInsets.all(5.0),
                      margin: EdgeInsets.all(5.0),
                      width: 150.0,
                      color: Colors.red,
                      child: Text(testList[index]),
                    );
                  ,

                ),
                //),
                //),
              ),

              ...

Main.dart

  void _loadSheetDatabases() 
    BottomSheetWidget bottomSheetwidget = BottomSheetWidget();
    bottomSheetwidget.loadMe();
  

【问题讨论】:

【参考方案1】:

在我看来,ListView.Builder 返回的小部件中缺少 Key,请尝试将 UniqueKey() 或 ValueKey 放入容器或文本中:

Container(
   key: UniqueKey(),
   padding: EdgeInsets.all(5.0),
   margin: EdgeInsets.all(5.0),
   width: 150.0,
   color: Colors.red,
   child: Text(testList[index]),
);

【讨论】:

感谢它实际上对我有用。 UniqueKey 使它工作。唯一的区别是我没有使用 setState 而是将数据推送到流 为我工作。没有它 setState 什么也没做。 setState 有时不适用于inheritedWidget。添加 UniqueKey() 成功了。谢谢;) 这应该是公认的答案。像魅力一样工作。 这个答案是救命稻草【参考方案2】:

您的ListView 仅在您的FloatingActionButton 上调用onPressed 时构建。 我认为这就是为什么当状态发生变化时它不会再次构建的原因。

您可以包装代码以在具有自己状态的新 StatefulWidget 中构建 ListView,然后在 testList 更改时更新它。

【讨论】:

所以,第二个dart 文件,extends StatefulWidget,然后是 CreateState,新类扩展 State,然后有 Widget build(BC ctx) return BottomSheet( builder: .... 是的,应该可以!您可以添加一个名为 updateList(List&lt;String&gt; list) 的方法并持有对小部件的引用以更新它 嗯,似乎无法正常工作。我已经更新了问题

以上是关于数据更新后颤振列表视图不更新的主要内容,如果未能解决你的问题,请参考以下文章

检索数据表单数据库后列表视图不更新

删除项目后如何更新列表视图?

颤振状态不会更新

删除子视图中的核心数据后更新表视图

数据库更新时更新列表视图

在列表视图多选中设置状态后,颤振布尔值重置