Flutter GridView.builder过滤数据后如何移除空白卡片消除空隙
GridView.builder 过滤后出现空白占位卡片问题修复
问题表现
使用GridView.builder实现商品网格列表时,需仅展示id匹配的商品项,尝试过设置padding: EdgeInsets.zero、用SizedBox.shrink替换不符合项组件的方案均无效,当前对不符合过滤条件的项返回空Card(),导致网格中出现大量空白占位,异常效果如下:
原有问题代码如下:
Stack( children: [ StreamBuilder( stream: FirebaseFirestore.instance.collection('products').snapshots(), builder: (context, AsyncSnapshot<QuerySnapshot> snapshot){ if(snapshot.hasError){ return Text("Error: ${snapshot.error}"); } if(snapshot.hasData){ return Column( children: [ Flexible( child: GridView.builder( padding: EdgeInsets.zero, itemCount: snapshot.data!.docs.length, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, mainAxisSpacing: 15, crossAxisSpacing: 15, childAspectRatio: 2/3, ), itemBuilder: (context, index){ final DocumentSnapshot documentSnapshot = snapshot.data!.docs[index]; DateTime dt = (documentSnapshot['endDateTime'] as Timestamp).toDate(); if(documentSnapshot['userid'] == widget.sellerId){ print(documentSnapshot['userid']); return buildImageCard( documentSnapshot['imageURL'][0], documentSnapshot['nameP'], documentSnapshot['startPrice'], dt, documentSnapshot['id'], documentSnapshot['categoryP'] ); } return Card(); } ) ), ], ); } return const Center( child: CircularProgressIndicator(), ); } ), ], );
问题原因
GridView会严格按照itemCount参数的值生成对应数量的网格占位,当前代码传入的是全量商品列表的长度,不管内容是否符合过滤规则,每个索引都会预留固定的网格位置- 在
itemBuilder中对不符合条件的项返回空Card()、SizedBox.shrink这类组件,只会让对应占位的内容变为空白,不会删除网格本身的占位,因此会出现大量空白格。
修复方法
不要在itemBuilder中做过滤判断,在渲染GridView前先完成列表过滤,只把符合条件的有效数据传给GridView渲染,修正后代码如下:
Stack( children: [ StreamBuilder( stream: FirebaseFirestore.instance.collection('products').snapshots(), builder: (context, AsyncSnapshot<QuerySnapshot> snapshot){ if(snapshot.hasError){ return Text("Error: ${snapshot.error}"); } if(snapshot.hasData){ // 提前过滤出符合条件的商品 final validProductList = snapshot.data!.docs.where( (doc) => doc['userid'] == widget.sellerId ).toList(); return Column( children: [ Flexible( child: GridView.builder( padding: EdgeInsets.zero, // itemCount使用过滤后有效列表的长度 itemCount: validProductList.length, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, mainAxisSpacing: 15, crossAxisSpacing: 15, childAspectRatio: 2/3, ), itemBuilder: (context, index){ // 直接从过滤后的有效列表取数据,无需额外判断 final DocumentSnapshot documentSnapshot = validProductList[index]; DateTime dt = (documentSnapshot['endDateTime'] as Timestamp).toDate(); return buildImageCard( documentSnapshot['imageURL'][0], documentSnapshot['nameP'], documentSnapshot['startPrice'], dt, documentSnapshot['id'], documentSnapshot['categoryP'] ); } ) ), ], ); } return const Center( child: CircularProgressIndicator(), ); } ), ], );
补充:如果需要做Firestore端的过滤,也可以直接在查询时加
where('userid', isEqualTo: widget.sellerId)条件,从数据源层面减少无效数据拉取,性能更优。
内容的提问来源于stack exchange,提问作者Nazhim
相关产品推荐
相关产品推荐

