Flutter —— 通讯录页面
1. 通讯录页面
做完了发现页面和我的页面,接下来做通讯录页面。将_currentIndex 改成1方便开发。 发现通讯录页面还是要用到之前的_themColor,那么就将_themColor抽取出来以便公用。 创建一个文件来存放这些需要公用的常量。然后放入主题色之后,在别的地方import这个文件就能使用了。
//主题色 const Color weChatThemColor = Color.fromRGBO(220, 220, 220, 1.0);复制代码
然后就可以将通讯录页面的Appbar的背景色改为weChatThemColor了,接下来要添加右上角的按钮,这里就可以用AppBar里面的actions。在actions里面添加一个图片,这里可以放多个,多个的话会从左到右排列。
actions: [ Container( margin: EdgeInsets.only(right: 10), child: Image( image: AssetImage("images/icon_friends_add.png"), height: 20, width: 20, ), ), ],复制代码
接着在Container外面包一层GestureDetector来添加手势响应。
接下来要做通讯录页的cell,那么如果只有通讯录页里面用,则可以放在一个文件里面,因为在一个文件里面,所以可以使用_令其私有,私有后本文件里面依然可以使用。
class _FriendCell extends StatelessWidget { _FriendCell({this.imageUrl, this.name, this.groupTitle, this.imageAssets}); final String? imageUrl; final String? name; final String? groupTitle; final String? imageAssets; @override Widget build(BuildContext context) { return Container(); } }复制代码
根据需要的内容创建模型
class Friends { Friends({this.imageUrl, this.name, this.indexLetter,this.ImageAssets}); final String? imageUrl; final String? name; final String? indexLetter; final String? ImageAssets; }复制代码
创建完之后,可以将通讯录页面scaffold里面的body设为:
Container( child: ListView.builder( itemBuilder: _itemForRow, itemCount: datas.length + _headerData.length, ), color: weChatThemColor, ),`复制代码
接下来添加头部四个的数据,这里是asset图片所以传ImageAssets。
final List<Friends> _headerData = [ Friends(ImageAssets: 'images/新的朋友.png', name: '新的朋友'), Friends(ImageAssets: 'images/群聊.png', name: '群聊'), Friends(ImageAssets: 'images/标签.png', name: '标签'), Friends(ImageAssets: 'images/公众号.png', name: '公众号'), ];复制代码
然后构建_itemForRow方法,就是在_itemForRow里面判断如果小于_headerData的长度,则传入imageAssets,否则就是imageUrl。注意这里datas的index需要减去_headerData的长度,否则会缺少前面几个数据。
Widget _itemForRow(BuildContext context, int index) { if (index < _headerData.length) { return _FriendCell( imageAssets: _headerData[index].ImageAssets, name: _headerData[index].name); } else { return _FriendCell( imageUrl: datas[index - _headerData.length].imageUrl, name: datas[index - _headerData.length ].name); } }复制代码
然后开始写界面,这里简单的使用一个Row来包含图片和昵称,然后使用ClipRRect将图片剪裁为圆角矩形,并且判断imageUrl是否为空,不为空则使用NetworkImage加载网络图片,否则就使用AssetImage加载本地图片。
Widget build(BuildContext context) { return Container( color: Colors.white, child: Row( children: [ Container( margin: EdgeInsets.all(10), width: 34, height: 34, child: ClipRRect( //剪裁为圆角矩形 borderRadius: BorderRadius.circular(5.0), child: Image( image: imageUrl != null ? NetworkImage(imageUrl!) : AssetImage(imageAssets ?? "") as ImageProvider, height: 20, width: 20, ) ), ), //图片 Container( child: Text(name ?? "",style: const TextStyle(fontSize: 18),), ), //昵称 ], ), );复制代码
运行后得到:
发现少了下划线,那么这里看到下划线是从昵称开始的,这里就可以选择将昵称和下划线做成一个整体。
Container( width: screenWidth(context) - 54, child: Column( children: [ Container( child: Text(name ?? "", style: const TextStyle(fontSize: 18)), alignment: Alignment.centerLeft, height: 54, ), Container( color: weChatThemColor, height: 0.5, ) ], ), ), //昵称复制代码
接下来要实现分组显示,在_itemForRow中多传一个groupTitle,这里在else添加因为上面的没有title。
Widget _itemForRow(BuildContext context, int index) { if (index < _headerData.length) { return _FriendCell( imageAssets: _headerData[index].ImageAssets, name: _headerData[index].name); } else { return _FriendCell( imageUrl: datas[index - _headerData.length].imageUrl, name: datas[index - _headerData.length].name, groupTitle: datas[index - _headerData.length].indexLetter, ); }复制代码
然后到_FriendCell里面将刚才的内容用Column包起来,然后在cell内容上面添加头部。
在头部里面设置alignment为Alignment.centerLeft,为了避免文字太左边给个10的内边距,然后根据是否有groupTitle判断是否显示这个控件。
Container( alignment: Alignment.centerLeft, padding: EdgeInsets.only(left: 10), height: groupTitle != null ? 30 : 0, color: weChatThemColor, child: groupTitle != null ? Text(groupTitle!,style: TextStyle(color: Colors.grey),) : null, ), 复制代码
这里还需要对数据进行排序,那么这里先声明一个_listDatas,然后在initState的时候进行添加数据,然后根据数据的indexLetter进行排序。
void initState() { // TODO: implement initState super.initState(); //_listDatas = []; _listDatas.addAll(datas); _listDatas.sort((Friends a,Friends b) { return (a.indexLetter ?? "").compareTo(b.indexLetter ?? ""); }); }复制代码
然后在_itemForRow里面根据判断当前indexLetter和前面一个indexLetter是否相等来判断是否传groupTitle。
Widget _itemForRow(BuildContext context, int index) { if (index < _headerData.length) { return _FriendCell( imageAssets: _headerData[index].ImageAssets, name: _headerData[index].name); } bool _hiddenIndexLetter = index - 4 > 0 && _listDatas[index - _headerData.length].indexLetter == _listDatas[index - _headerData.length - 1].indexLetter; return _FriendCell( imageUrl: _listDatas[index - _headerData.length].imageUrl, name: _listDatas[index - _headerData.length].name, groupTitle: _hiddenIndexLetter ? null : _listDatas[index - _headerData.length].indexLetter, ); }
作者:大林晓鹿
链接:https://juejin.cn/post/7030231738752172046