Flutter中如何实现API获取联系人的选择功能及UI定制?
联系人列表UI定制与API数据获取解决方案
我在UI定制上遇到问题,参考图为分组式联系人列表(带首字母分组标题、选中项高亮+勾选标记),尝试自定义效果未果。同时想了解如何实现从API获取联系人并添加选择功能。当前代码如下:
ListView( children: con.contactOwnerList.map((element) { return Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( element.name .toString() .toUpperCase() .characters .first, ), Container( color: Theme.of(context).colorScheme.onPrimary, child: ListTile( leading: const CircleAvatar(), title: Text('${element.name}'), subtitle: Text('${element.email}'), trailing: SvgPicture.asset( Assets.images.svg.createCase.circleCheck), onTap: () {}, ), ), const Divider() ], ); }).toList(), ),
一、UI定制实现(匹配参考图效果)
- 首字母分组标题优化:给分组字母添加加粗、灰色字体、左右间距,避免和列表项拥挤在一起
- 选中状态控制:维护选中ID集合,点击列表项时切换状态,动态显示勾选图标并高亮背景
- 布局简化:移除多余容器,用
ListTile自带的selected属性实现高亮,自定义分割线缩进对齐内容
二、API获取联系人与选择功能实现
- API数据获取:在页面初始化时发起请求,获取数据后更新列表,同时处理加载、错误状态
- 选择状态管理:用
Set存储选中的联系人ID,点击时添加/移除 - 状态联动:UI根据选中状态自动更新样式
修改后的完整代码示例
class ContactListScreen extends StatefulWidget { const ContactListScreen({super.key}); @override State<ContactListScreen> createState() => _ContactListScreenState(); } class _ContactListScreenState extends State<ContactListScreen> { final ContactController con = Get.find<ContactController>(); // 替换为你的状态管理方式 final Set<String> _selectedContactIds = {}; bool _isLoading = true; @override void initState() { super.initState(); _fetchContactsFromApi(); } // 从API拉取联系人数据 Future<void> _fetchContactsFromApi() async { try { setState(() => _isLoading = true); // 替换为你的实际API请求逻辑 final contacts = await ApiService.getContacts(); con.contactOwnerList.assignAll(contacts); } catch (e) { debugPrint('获取联系人失败:$e'); // 可添加错误提示弹窗 } finally { setState(() => _isLoading = false); } } // 切换联系人选中状态 void _toggleContactSelection(String contactId) { setState(() { _selectedContactIds.contains(contactId) ? _selectedContactIds.remove(contactId) : _selectedContactIds.add(contactId); }); } @override Widget build(BuildContext context) { if (_isLoading) { return const Center(child: CircularProgressIndicator()); } return ListView.builder( itemCount: con.contactOwnerList.length, itemBuilder: (context, index) { final element = con.contactOwnerList[index]; final isSelected = _selectedContactIds.contains(element.id); // 判断是否显示首字母分组标题(当前项首字母与上一项不同时显示) final showGroupTitle = index == 0 || element.name.toString().toUpperCase()[0] != con.contactOwnerList[index-1].name.toString().toUpperCase()[0]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 首字母分组标题 if (showGroupTitle) Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Text( element.name.toString().toUpperCase()[0], style: const TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: Colors.grey, ), ), ), // 联系人列表项 ListTile( leading: CircleAvatar( child: Text(element.name.toString().toUpperCase()[0]), // 动态显示首字母 ), title: Text(element.name), subtitle: Text(element.email), trailing: isSelected ? SvgPicture.asset(Assets.images.svg.createCase.circleCheck) : null, selected: isSelected, selectedTileColor: Theme.of(context).colorScheme.primaryContainer, // 选中高亮背景 onTap: () => _toggleContactSelection(element.id), ), // 缩进分割线 const Divider(height: 1, indent: 72), ], ); }, ); } }
补充说明
- 替换
ApiService.getContacts()为你的实际API请求方法,确保返回的联系人模型包含id字段 - 若使用GetX/Provider等状态管理框架,可将
_selectedContactIds移至ViewModel中,实现跨组件状态同步 - 头像部分可根据需求替换为联系人头像图片,增强视觉效果
内容的提问来源于stack exchange,提问作者Tinut Chan
相关产品推荐
相关产品推荐

