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