如何在Flutter ListView中添加对应未付款人数的dummy占位组件
Flutter ListView追加未付款用户占位组件实现方案
问题场景
通过JSON API返回的已付款用户列表渲染横向ListView,接口同时返回剩余未付款人数numberOfUserLeft,需要在已付款用户条目后追加dummy占位组件,展示剩余未付款用户状态,参考效果如下:
原有实现存在三个核心问题:
itemCount仅计算了已付款用户的长度,没有预留占位组件的位置itemBuilder没有分支判断逻辑,无法区分渲染真实用户和占位组件- 冗余布局问题:原有
itemBuilder中每个条目内重复写了两个完全一致的用户头像组件,会导致单条目显示重复内容
实现步骤
- 初始化变量时设置空安全默认值,避免初始加载阶段空报错
// 初始化时给默认值 List data = []; int numberOfUserLeft = 0; bool isLoadingActivity = false;
- 接口数据解析时把人数转成整数类型,避免接口返回字符串类型导致计算错误
this.setState(() { data = json.decode(response.body); isLoadingActivity = false; // 转成int类型,兼容接口返回字符串数字的场景 numberOfUserLeft = int.parse(data[0]['userCount'].toString()); });
- 修改
ListView配置,调整itemCount总长度,在itemBuilder中分支渲染真实用户和占位组件
ListView.builder( scrollDirection: Axis.horizontal, // 总条目数 = 已付款用户数 + 未付款占位数量 // 如果只需要1个组件显示总剩余人数,把numberOfUserLeft改成1即可 itemCount: data.length + numberOfUserLeft, itemBuilder: (context, position) { // 索引在已付款用户范围内:渲染真实已付款用户组件 if (position < data.length) { return Container( padding: EdgeInsets.all(10), child: Container( padding: EdgeInsets.all(4), child: Stack( clipBehavior: Clip.none, children: [ CircleAvatar( radius: 60, backgroundColor: colorGreen, child: Container( padding: EdgeInsets.all(4), margin: EdgeInsets.all(3), decoration: BoxDecoration( color: Colors.white, shape: BoxShape.circle, ), child: ClipOval( child: Container( height: 250, width: 250, child: data[position]["profile_img"] != null ? Image.network( data[position]["profile_img"], fit: BoxFit.cover, ) : Image.asset("assets/person_icon.png"), ), ), ), ), Positioned( bottom: 100, right: 45, child: InkWell( onTap: () {}, child: Center( child: CircleAvatar( backgroundColor: colorGreen, radius: 15.0, child: Icon( Icons.check, color: Colors.white, size: 25, ), ), ), ), ), ], ), ), ); } // 索引超出已付款用户范围:渲染占位dummy组件 else { // 判断是否是最后一个占位项,最后一个项显示剩余人数 bool isLastPlaceHolder = position == data.length + numberOfUserLeft - 1; return Container( padding: EdgeInsets.all(10), child: Container( padding: EdgeInsets.all(4), child: CircleAvatar( radius: 60, backgroundColor: Colors.grey[300], child: Container( padding: EdgeInsets.all(4), margin: EdgeInsets.all(3), decoration: BoxDecoration( color: Colors.white, shape: BoxShape.circle, ), child: ClipOval( child: Container( height: 250, width: 250, alignment: Alignment.center, child: isLastPlaceHolder ? Text( "+$numberOfUserLeft", style: TextStyle( fontSize: 32, fontWeight: FontWeight.bold, color: Colors.grey[600], ), ) : Image.asset( "assets/person_icon.png", color: Colors.grey[400], fit: BoxFit.cover, ), ), ), ), ), ), ); } }, )
自定义调整说明
- 如果不需要给每个未付款用户都渲染单独的灰色头像占位,仅需要一个组件显示剩余总人数,直接把
itemCount改成data.length + 1即可,不需要判断isLastPlaceHolder,直接渲染带+numberOfUserLeft文字的组件就行 - 占位组件的样式可以根据设计稿调整尺寸、颜色、文字大小
- 如果需要给占位组件添加点击交互(比如点击跳转邀请付款页面),直接给占位组件的
InkWell添加对应onTap逻辑即可
内容的提问来源于stack exchange,提问作者mideveloper
相关产品推荐
相关产品推荐

