Flutter:GestureDetector 中的 setState() 不起作用
Flutter: setState() inside GestureDetector is not working
在我的代码中,我将网络图像加载到网格中。然后我允许用户通过从他们自己的图库中选择一个来替换网络图像。请检查以下代码。
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
似乎在工作,即使它被调用了。
为什么会发生这种情况,我该如何解决?
您的变量 XFile? imageFile;
是在 _buildPhotoSection
函数中定义的 - 而不是在小部件本身中。所以你实际上是在 setState() 调用中更新局部变量。一旦 setState() 完成 - 它会通知 Flutter 引擎重建小部件 - 并且您的 imageFile 变量将被重新初始化 - 不保存您在上一次迭代中设置的值。
我认为你应该将 XFile? imageFile;
和 bool check = false;
移动到 class 级别,这应该可以解决问题。
编辑:在您对多张图片发表评论后 - 这是我的建议:
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 是否包含索引键,并基于该图像应该呈现。
我没有尝试编译这个,所以那里可能有一些错误。
在我的代码中,我将网络图像加载到网格中。然后我允许用户通过从他们自己的图库中选择一个来替换网络图像。请检查以下代码。
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
似乎在工作,即使它被调用了。
为什么会发生这种情况,我该如何解决?
您的变量 XFile? imageFile;
是在 _buildPhotoSection
函数中定义的 - 而不是在小部件本身中。所以你实际上是在 setState() 调用中更新局部变量。一旦 setState() 完成 - 它会通知 Flutter 引擎重建小部件 - 并且您的 imageFile 变量将被重新初始化 - 不保存您在上一次迭代中设置的值。
我认为你应该将 XFile? imageFile;
和 bool check = false;
移动到 class 级别,这应该可以解决问题。
编辑:在您对多张图片发表评论后 - 这是我的建议:
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 是否包含索引键,并基于该图像应该呈现。
我没有尝试编译这个,所以那里可能有一些错误。