import 'package:azlistview/azlistview.dart'; import 'package:flutter/material.dart'; import 'package:lpinyin/lpinyin.dart'; class ContactInfo extends ISuspensionBean { final String name; final String avatar; String? tagIndex; String? namePinyin; ContactInfo({ required this.name, required this.avatar, this.tagIndex, this.namePinyin, }); @override String getSuspensionTag() => tagIndex ?? '#'; } /// ================= Page ================= class ContactsPage extends StatefulWidget { const ContactsPage({super.key}); @override State createState() => _ContactsPageState(); } class _ContactsPageState extends State { List contactList = []; List topList = []; @override void initState() { super.initState(); _loadFakeData(); } void _loadFakeData() { contactList = [ ContactInfo( name: '张三', avatar: 'https://randomuser.me/api/portraits/men/11.jpg', ), ContactInfo( name: '李四', avatar: 'https://randomuser.me/api/portraits/men/12.jpg', ), ContactInfo( name: '王五', avatar: 'https://randomuser.me/api/portraits/men/13.jpg', ), ContactInfo( name: '赵六', avatar: 'https://randomuser.me/api/portraits/women/14.jpg', ), ContactInfo( name: '陈七', avatar: 'https://randomuser.me/api/portraits/women/15.jpg', ), ContactInfo( name: '刘八', avatar: 'https://randomuser.me/api/portraits/men/16.jpg', ), ContactInfo( name: '周九', avatar: 'https://randomuser.me/api/portraits/men/17.jpg', ), ContactInfo( name: '吴十', avatar: 'https://randomuser.me/api/portraits/women/18.jpg', ), ContactInfo( name: '欧阳峰', avatar: 'https://randomuser.me/api/portraits/men/21.jpg', ), ContactInfo( name: '诸葛青', avatar: 'https://randomuser.me/api/portraits/men/22.jpg', ), ContactInfo( name: '司马光', avatar: 'https://randomuser.me/api/portraits/men/23.jpg', ), ContactInfo( name: '慕容复', avatar: 'https://randomuser.me/api/portraits/women/24.jpg', ), ContactInfo( name: '安琪拉', avatar: 'https://randomuser.me/api/portraits/women/31.jpg', ), ContactInfo( name: '亚瑟', avatar: 'https://randomuser.me/api/portraits/men/32.jpg', ), ContactInfo( name: '李白', avatar: 'https://randomuser.me/api/portraits/men/33.jpg', ), ContactInfo( name: '韩信', avatar: 'https://randomuser.me/api/portraits/men/34.jpg', ), ContactInfo( name: '孙尚香', avatar: 'https://randomuser.me/api/portraits/women/35.jpg', ), ContactInfo( name: '鲁班', avatar: 'https://randomuser.me/api/portraits/men/36.jpg', ), ContactInfo( name: '妲己', avatar: 'https://randomuser.me/api/portraits/women/37.jpg', ), ContactInfo( name: '甄姬', avatar: 'https://randomuser.me/api/portraits/women/38.jpg', ), ]; _handleList(contactList); } void _handleList(List list) { for (var item in list) { final pinyin = PinyinHelper.getPinyinE(item.name); final tag = pinyin.substring(0, 1).toUpperCase(); item.namePinyin = pinyin; item.tagIndex = RegExp(r'[A-Z]').hasMatch(tag) ? tag : '#'; } SuspensionUtil.sortListBySuspensionTag(list); SuspensionUtil.setShowSuspensionStatus(list); setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF2F2F7), appBar: AppBar( automaticallyImplyLeading: false, backgroundColor: Colors.grey.shade200, elevation: 0, centerTitle: true, title: const Text( '通讯录', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: Color(0xFF1C1C1E), ), ), ), body: Column( children: [_buildSearchBar(), Expanded(child: _buildAzListView())], ), ); } Widget _buildAzListView() { return AzListView( data: contactList, itemCount: contactList.length, itemBuilder: (_, index) { final c = contactList[index]; return Container( color: Colors.white, child: ListTile( leading: CircleAvatar( backgroundImage: NetworkImage(c.avatar), onBackgroundImageError: (_, __) {}, ), title: Text( c.name, style: const TextStyle(fontSize: 16, color: Color(0xFF1C1C1E)), ), ), ); }, susItemBuilder: (_, index) { final tag = contactList[index].getSuspensionTag(); return Container( height: 28, padding: const EdgeInsets.symmetric(horizontal: 16), alignment: Alignment.centerLeft, color: const Color(0xFFF2F2F7), child: Text( tag, style: const TextStyle(fontSize: 13, color: Color(0xFF8E8E93)), ), ); }, indexBarData: [...kIndexBarData], indexBarOptions: IndexBarOptions( textStyle: const TextStyle(fontSize: 12, color: Color(0xFF8E8E93)), selectItemDecoration: const BoxDecoration( shape: BoxShape.circle, color: Colors.green, ), ), ); } Widget _buildSearchBar() { return Container( height: 44, decoration: BoxDecoration( color: Colors.white, ), child: TextField( textAlignVertical: TextAlignVertical.center, decoration: InputDecoration( hintText: '搜索联系人', hintStyle: const TextStyle(fontSize: 15, color: Color(0xFF8E8E93)), prefixIcon: const Icon( Icons.search, size: 20, color: Color(0xFF8E8E93), ), border: InputBorder.none, contentPadding: const EdgeInsets.symmetric(vertical: 12), ), ), ); } }