「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战」。
1. 宏定义
我们在项目中使用一些公共的类比如我们iOS的宏定义
,在flutter中也有类似的我们直接创建一个文件,类似我们的iOS中的头文件
,之后定义一些常用的类,比如颜色,标题样式等。使用的时候直接option+enter
自动导入报错的即可
Color ThemeColor = const Color.fromRGBO(220, 220, 220, 1.0);
TextStyle TitleStyle = const TextStyle(fontSize: 16,fontWeight: FontWeight.bold,color: Colors.black);
复制代码
2. 导航栏
appBar: AppBar(
title: const Text('通讯录页面'),
centerTitle: true,
elevation: 0.0,
backgroundColor: ThemeColor,
actions: [
GestureDetector(
onTap: (){
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => DiscoverChildPage("添加朋友")));
},
child:Container(
padding: EdgeInsets.only(right: 15),
child: Image.asset('images/icon_friends_add.png',width: 30,),
)
),
],
leading: IconButton(onPressed: (){
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => DiscoverChildPage("更多")));
}, icon: Icon(Icons.menu)) ,
),
复制代码
其中主要介绍下actions
和leading
actions
是一个数组
元素为控件widget
我们在添加一个
相当于iOS导航栏中的rightButtonItems
我们可以添加多个widege
- leading
相当于导航栏左控件返回一个widget
leading: IconButton(onPressed: (){
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => DiscoverChildPage("更多")));
}, icon: Icon(Icons.menu)) ,
复制代码
添加2个的话需要注意尺寸我这里直接使用了IconButton
尺寸不对报错
3. 数据处理
我们定义数据
class Friends {
Friends({this.imageUrl, this.name, this.indexLetter, this.imageAssets});
final String? imageAssets;
final String? imageUrl;
final String? name;
final String? indexLetter;
}
List<Friends> datas = [
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/27.jpg',
name: 'Lina',
indexLetter: 'L'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/17.jpg',
name: '菲儿',
indexLetter: 'F'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/16.jpg',
name: '安莉',
indexLetter: 'A'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/men/31.jpg',
name: '阿贵',
indexLetter: 'A'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/22.jpg',
name: '贝拉',
indexLetter: 'B'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/37.jpg',
name: 'Lina',
indexLetter: 'L'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/18.jpg',
name: 'Nancy',
indexLetter: 'N'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/men/47.jpg',
name: '扣扣',
indexLetter: 'K'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/men/3.jpg',
name: 'Jack',
indexLetter: 'J'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/5.jpg',
name: 'Emma',
indexLetter: 'E'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/24.jpg',
name: 'Abby',
indexLetter: 'A'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/men/15.jpg',
name: 'Betty',
indexLetter: 'B'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/men/13.jpg',
name: 'Tony',
indexLetter: 'T'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/men/26.jpg',
name: 'Jerry',
indexLetter: 'J'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/men/36.jpg',
name: 'Colin',
indexLetter: 'C'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/12.jpg',
name: 'Haha',
indexLetter: 'H'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/11.jpg',
name: 'Ketty',
indexLetter: 'K'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/13.jpg',
name: 'Lina',
indexLetter: 'L'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/23.jpg',
name: 'Lina',
indexLetter: 'L'),
];
复制代码
数据包含一个固定的上面4个
和下面联系人
先定义头的数据
final List<Friends> _headerData = [
Friends(imageAssets: 'images/新的朋友.png', name: '新的朋友'),
Friends(imageAssets: 'images/群聊.png', name: '群聊'),
Friends(imageAssets: 'images/标签.png', name: '标签'),
Friends(imageAssets: 'images/公众号.png', name: '公众号'),
];
复制代码
4. Cell的创建
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(
child: Column(
children: [
//头部,没有标题的话不显示
Container(
child: groupTitle !=null ? Text(groupTitle!,style: TextStyle(color: Colors.grey),) : null,
height: groupTitle != null ?30:0,
color: ThemeColor,
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: 15),
),
Container(//cell内容
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(margin: EdgeInsets.all(10),child:imageAssets == null ? Image.network(imageUrl!,width: 34,height: 34,) : Image.asset(imageAssets!),height: 34,width: 34,),//头像
Container(
alignment: Alignment.centerLeft,
width: screenWidth(context) -54,
child: Column(
children: [
Container(alignment: Alignment.centerLeft,padding: EdgeInsets.only(left: 15),child: Text(name!,style: TitleStyle,),height: 54,),//姓名
Container(color: ThemeColor,height: 0.5,),
],),)
],
),
)
],
),
);
}
}
复制代码
我们定义下listView
,使用ListView.builder
的形式处理,类似我们iOS的cell的复用
表现形式而不是静态cell
- itemBuilder
我们定义下头数组和联系人数组,数据为之前我们定义的
final List<Friends> _headerData = [
Friends(imageAssets: 'images/新的朋友.png', name: '新的朋友'),
Friends(imageAssets: 'images/群聊.png', name: '群聊'),
Friends(imageAssets: 'images/标签.png', name: '标签'),
Friends(imageAssets: 'images/公众号.png', name: '公众号'),
];
final List<Friends> _listDatas = [];
Widget _itemBuilder(BuildContext context, int index) {
if (index < _headerData.length) {
//前4个
return FriendCell(imageAssets: _headerData[index].imageAssets,
name: _headerData[index].name,);
} else {
return FriendCell(imageAssets: _listDatas[index - _headerData.length].imageAssets,
name: _listDatas[index - _headerData.length].name,);
}
}
复制代码
这里进行区分,分为前4个和后面的。在listView
展示
child: ListView.builder(itemBuilder: _itemBuilder,
itemCount: _headerData.length+_listDatas.length,
复制代码
效果大致如下
我们添加一下_listDatas
的数据
@override
void initState() {
// TODO: implement initState
super.initState();
_listDatas
..addAll(datas)
..addAll(datas);
//排序
_listDatas.sort((Friends a, Friends b) {
return a.indexLetter!.compareTo(b.indexLetter!);
});
}
复制代码
初始化状态
的时候我们进行数据的添加和处理,通过数组的sort
方法进行排序,比较它们两两的首字母
,按顺序进行排序
。
- 分组标题
我们的cell只有传入组标题的时候
才会进行展示,那么我们只要判断当前数组的元素每一个
和下一个
比较,如果首字母相同就不展示
,说明展示过了
bool isHideGroupTitle = (index -_headerData.length>0 &&_listDatas[index-_headerData.length].indexLetter == _listDatas[index-_headerData.length-1].indexLetter);
复制代码
头部的组固定
的,当前列表比如第5
个数据的时候,index =4
,则index -_headerData.length>0
为false
。所以展示头
Widget _itemBuilder(BuildContext context, int index) {
bool isHideGroupTitle = (index -_headerData.length>0 &&_listDatas[index-_headerData.length].indexLetter == _listDatas[index-_headerData.length-1].indexLetter);
if (index < _headerData.length) {
//前4个
return FriendCell(imageAssets: _headerData[index].imageAssets,
name: _headerData[index].name,);
} else {
return FriendCell(
imageUrl: _listDatas[index - _headerData.length].imageUrl,
name: _listDatas[index - _headerData.length].name,
groupTitle: isHideGroupTitle?null: _listDatas[index - _headerData.length ].indexLetter,);
}
}
复制代码
下一篇实现右侧指示条,以及指示条的联动。