【发布时间】:2020-11-15 11:28:02
【问题描述】:
我正在学习 Provider,我的测试应用程序将图像从 Firestore 数据库绘制到 ListView 中。我想在 any 图像上使用 LongPress 来制作 whole 列表 toggle 并使用复选框选择器图标重绘,如下所示,类似于方式画廊作品:
我的代码可以工作,但它会在每个 LongPress 上抛出一个异常,指出“setState() 或 markNeedsBuild() 在构建期间被调用”,我正在努力尝试弄清楚如何延迟 ChangeNotifier 直到构建小部件树?或者其他方式来完成这项任务?
我的 Provider 类只接受我的 PictureModel 类的 List 并有一个通知听众的 toggleSelectors() 方法。代码如下:
class PicturesProvider with ChangeNotifier {
List<PictureModel> _pictures = [];
bool visible = false;
UnmodifiableListView<PictureModel> get allPictures => UnmodifiableListView(_pictures);
UnmodifiableListView<PictureModel> get selectedPictures =>
UnmodifiableListView(_pictures.where((pic) => pic.selected));
void addPictures(List<PictureModel> picList) {
_pictures.addAll(picList);
notifyListeners();
}
void toggleSelectors() {
visible = !visible;
_pictures.forEach((pic) {
pic.selectVisible = visible;
});
notifyListeners();
}
}
我有一个 SinglePicture UI 类,它将网络图像加载到 AspectRatio 小部件中,并用 GestureDetector 包装它以切换选择器并将它们呈现在 Stack 小部件的顶部,如下所示:
Widget build(BuildContext context) {
int originalHeight, originalWidth;
return AspectRatio(
aspectRatio: pictureModel.aspectRatio,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
FutureBuilder<ui.Image>(
future: _getImage(),
builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
if (snapshot.hasData) {
ui.Image image = snapshot.data;
originalHeight = image.height;
originalWidth = image.width;
return GestureDetector(
onLongPress: () => Provider.of<PicturesProvider>(context, listen: false).toggleSelectors(),
child: RawImage(
image: image,
fit: BoxFit.cover,
// if portrait image, move down slightly for headroom
alignment: Alignment(0, originalHeight > originalWidth ? -0.2 : 0),
),
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
Positioned(
left: 10.0,
top: 10.0,
child: pictureModel.selectVisible == false
? Container(
height: 0.0,
width: 0.0,
)
: pictureModel.selected == false
? Icon(
Icons.check_box_outline_blank,
size: 30.0,
color: Colors.white,
)
: Icon(
Icons.check_box,
size: 30.0,
color: Colors.white,
),
)
],
),
);
}
然后从我的 PicturesList UI 类调用这个 SinglePicture 类,该类只构建一个 ListView,如下所示:
class PicturesList extends StatelessWidget {
final List<PictureModel> pictures;
PicturesList({@required this.pictures});
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: pictures.length,
cacheExtent: 3,
itemBuilder: (context, index) {
return SinglePicture(
pictureModel: pictures[index],
);
},
);
}
然后从我的应用程序中的 FutureBuilder 调用整个 shebang,它构建应用程序,如下所示:
body: FutureBuilder(
future: appProject.fetchProject(), // Snapshot of database
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
// Get all picture URLs from project snapshot
List<dynamic> picUrls = snapshot.data['pictures'].map((pic) => pic['pic_cloud']).toList();
// Create list of PictureModel objects for Provider
List<PictureModel> pictures = picUrls.map((url) => PictureModel(imageUrl: url, imageHeight: 250.0, selectVisible: false)).toList();
// Add list of PictureModel objects to Provider for UI render
context.watch<PicturesProvider>().addPictures(pictures);
return SafeArea(
child: PicturesList(
pictures: context.watch<PicturesProvider>().allPictures,
),
);
} else if (snapshot.hasError) {
print('Error');
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
如果有人提示我如何在不引发异常的情况下完成此切换操作,我将不胜感激。提前谢谢!
【问题讨论】:
-
你误用了 FutureBuilder。请参阅stackoverflow.com/questions/52249578/… 了解更多信息
-
@RémiRousselet 谢谢您,先生。这解释了很多在我的代码中有点古怪的事情。现在唯一的问题是我必须回去重新考虑我所做的一切,以确保我的构建器方法是干净的。它虽然有效,但我会发布更新的代码供其他人查看,以防它有帮助。再次感谢!
标签: flutter asynchronous dart flutter-provider state-management