Flutter:GestureDetector 中的 setState() 不起作用

Posted

技术标签:

【中文标题】Flutter:GestureDetector 中的 setState() 不起作用【英文标题】:Flutter: setState() inside GestureDetector is not working 【发布时间】:2021-12-10 21:05:22 【问题描述】:

在我的代码中,我将网络图像加载到网格中。然后我允许用户通过从他们自己的图库中选择一个来替换网络图像。请检查以下代码。

Widget _buildPhotoSection() 
    return MediaQuery.removePadding(
      context: context,
      removeTop: true,
      child: GridView.builder(
          shrinkWrap: true,
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3,
          ),
          itemCount: 5,
          itemBuilder: (BuildContext context, int index) 
            XFile? imageFile;
            bool check = false;
            return GestureDetector(
              onTap: () async 
                final XFile? image =
                    await _picker.pickImage(source: ImageSource.gallery);

                setState(() 
                  imageFile = image;
                  check = true;
                  print("DONE");
                );
              ,
              child: Stack(
                children: [
                  Card(
                    color: Colors.amber,
                    child: Container(
                      padding: EdgeInsets.all(1),
                      child: check == false
                          ? index <= imageList.length - 1
                              ? CachedNetworkImage(
                                  width: 200,
                                  height: 150,
                                  imageUrl: imageList[index].imageURL == ""
                                      ? "https://www.freeiconspng.com/uploads/no-image-icon-6.png"
                                      : imageList[index].imageURL,
                                  placeholder: (context, url) =>
                                      CircularProgressIndicator(),
                                  errorWidget: (context, url, error) =>
                                      Icon(Icons.error),
                                  fit: BoxFit.fill,
                                )
                              : CachedNetworkImage(
                                  width: 200,
                                  height: 150,
                                  imageUrl:
                                      "https://www.freeiconspng.com/uploads/no-image-icon-6.png",
                                  placeholder: (context, url) =>
                                      CircularProgressIndicator(),
                                  errorWidget: (context, url, error) =>
                                      Icon(Icons.error),
                                  fit: BoxFit.fill,
                                )
                          : Image.file(
                              File(imageFile!.path),
                              width: 200,
                              height: 150,
                            ),
                    ),
                  ),
                  Align(
                      alignment: Alignment.bottomCenter,
                      child: TextButton(
                          onPressed: () ,
                          child: Text(
                            'Change',
                          )))
                ],
              ),
            );
          ),
    );
  

在这里我可以选择图片,但画廊中的图片永远不会显示。看起来 setState 正在工作,即使它被调用了。

为什么会发生这种情况,我该如何解决?

【问题讨论】:

【参考方案1】:

您的变量XFile? imageFile; 是在_buildPhotoSection 函数中定义的——而不是在小部件本身中。因此,您实际上是在 setState() 调用中更新局部变量。一旦 setState() 完成 - 它会通知 Flutter 引擎重建小部件 - 并且你的 imageFile 变量将被重新初始化 - 不保存你在之前的迭代中设置的值。

我认为您应该将 XFile? imageFile; bool check = false; 移至班级级别,这应该可以解决问题。

编辑:在您对多张图片发表评论后 - 这是我的建议:

var imageFile=<int, XFile>;

Widget _buildPhotoSection() 
    return MediaQuery.removePadding(
      context: context,
      removeTop: true,
      child: GridView.builder(
          shrinkWrap: true,
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3,
          ),
          itemCount: 5,
          itemBuilder: (BuildContext context, int index) 
//             XFile? imageFile;
            //bool check = false;
            return GestureDetector(
              onTap: () async 
                final XFile? image =
                    await _picker.pickImage(source: ImageSource.gallery);

                setState(() 
                  imageFile[index] = image;
                  //check = true;
                  print("DONE");
                );
              ,
              child: Stack(
                children: [
                  Card(
                    color: Colors.amber,
                    child: Container(
                      padding: EdgeInsets.all(1),
                      child: imageFile.containsKey(index) == false
                          ? index <= imageList.length - 1
                              ? CachedNetworkImage(
                                  width: 200,
                                  height: 150,
                                  imageUrl: imageList[index].imageURL == ""
                                      ? "https://www.freeiconspng.com/uploads/no-image-icon-6.png"
                                      : imageList[index].imageURL,
                                  placeholder: (context, url) =>
                                      CircularProgressIndicator(),
                                  errorWidget: (context, url, error) =>
                                      Icon(Icons.error),
                                  fit: BoxFit.fill,
                                )
                              : CachedNetworkImage(
                                  width: 200,
                                  height: 150,
                                  imageUrl:
                                      "https://www.freeiconspng.com/uploads/no-image-icon-6.png",
                                  placeholder: (context, url) =>
                                      CircularProgressIndicator(),
                                  errorWidget: (context, url, error) =>
                                      Icon(Icons.error),
                                  fit: BoxFit.fill,
                                )
                          : Image.file(
                              File(imageFile[index]!.path),
                              width: 200,
                              height: 150,
                            ),
                    ),
                  ),
                  Align(
                      alignment: Alignment.bottomCenter,
                      child: TextButton(
                          onPressed: () ,
                          child: Text(
                            'Change',
                          )))
                ],
              ),
            );
          ),
    );
  

您会注意到我将 imageFile 转换为地图 - 它将保存用户选择的索引和 XFile。我还删除了检查变量 - 我正在检查 Map 是否包含索引键,并基于该图像应该呈现。

我没有尝试编译这个,所以可能会有很少的错误。

【讨论】:

我做不到。这是图像的动态生成。我有 5 张图片,它们是由 Grid 生成器生成的。用户可以更新一个或多个图像,并且显示图像应该相应地更新。 所以您需要一个List&lt;Xfile&gt; imageFile - 即您的 GridVeiw 要显示的图像列表,并且每个 onTap 应该替换列表中的一个元素。但原理是一样的——你需要类级别的数据——这是你存储状态并启用 setState() 来操作它的地方。 我更新了我的答案,看看是否适合你。 谢谢。这确实有效。

以上是关于Flutter:GestureDetector 中的 setState() 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 中 GestureDetector 的使用误区

Flutter:GestureDetector 中的 setState() 不起作用

堆栈中 ListView 顶部的 GestureDetector 阻止滚动 - Flutter Web

Flutter 中 GestureDetector 的使用误区

Flutter 中 GestureDetector 的使用误区

flutter GestureDetector 点击空白区域无反应解决办法