前言
前面已经介绍过网络请求了,这里主要介绍聊天列表搭建,还有扫一扫那里的弹层,该弹层主要采用系统控件 PopupMenuButton
ps:如果想自己定制弹窗,前面有介绍Dialog的自定义
聊天列表
按照之前的介绍,其实ListView.builder
很容易就实现聊天列表,这里介绍他主要是引出 ListTile
类,至少能减少一些代码嵌套
先看看效果
代码如下所示:
//ListView.builder表格复用
ListView.builder(
itemBuilder: itemForRow,
itemCount: list.length,
)
//Row的效果如下
Widget itemForRow(BuildContext context, int index) {
//这个就是跟微信首页聊天的一样,可以设置图片,标题内容
final item = list[index];
//使用ListTile组件
return ListTile(
//设置标题
title: Text(item.name,
style: const TextStyle(fontSize: 12, color: Colors.black87)),
//设置子标题
subtitle: Text(
item.message,
style: const TextStyle(fontSize: 12, color: Colors.black87),
overflow: TextOverflow.ellipsis, //设置省略效果
),
//设置左侧视图
leading: CircleAvatar(backgroundImage: NetworkImage(item.imgUrl)),
);
}
复制代码
ListTile
默认没有下划线,如果想要下划线,外面包裹一层就可以了,如下所示
Column(
children: [
ListTile(
title: Text(item.name,
style: const TextStyle(fontSize: 12, color: Colors.black87)),
subtitle: Text(
item.message,
style: const TextStyle(fontSize: 12, color: Colors.black87),
overflow: TextOverflow.ellipsis, //设置省略效果
),
leading: CircleAvatar(backgroundImage: NetworkImage(item.imgUrl)),
),
Row(
children: [
//两个Container都可以
Container(width: 46, height: 1, color: Colors.white),
//Container内容默认不会填充满整个屏幕
Expanded(child: Container(height: 1, color: const Color.fromRGBO(0xe1, 0xe1, 0xe1, 1))),
],
)
],
);
复制代码
聊天数据
通过 http
框架请求,然后一步一步翻译成我们使用的 class 类
//这里主要简介数据获取,网络失败后的 catch 自行处理即可
Future<List<dynamic>> getData() async {
//使用 http 框架的 get请求网络数据,请求的结果在body中,为 json字符串
Response res = await get(
Uri.parse("http://rap2api.taobao.org/app/mock/224518/api/chat/list"));
//通过系统的 dart:convert 框架, 使用jsonDecode将json字符串转化为map
final body = jsonDecode(res.body);
//取出数据,转化为我们的类
final chatList = body["chat_list"];
for (final item in chatList) {
// fromJson为我们定义的工厂构造方法,将 Map 转化为我们的对象
final chatData = ChatListData.formJson(item);
list.add(chatData);
}
return list;
}
复制代码
ChatListData
类的定义如下所示,由于没有看到 dart
反射相关,这部分内容只能自己编写了(不像JavaScript
没有class
类的限制可以直接赋值与调用)
class ChatListData {
final String imgUrl;
final String name;
final String message;
ChatListData({required this.imgUrl, required this.name, required this.message});
factory ChatListData.formJson(Map<String, dynamic> json) {
return ChatListData(
imgUrl: json["imageUrl"],
name: json['name'],
message: json['message']);
}
}
复制代码
扫一扫弹层
点击微信聊天页右上角加号,弹出扫一扫的点击界面,先看效果
先声明一下右侧弹层的数据信息,这里直接采用的 Map
解决,字节也可以放到一个类中,如下所示
List popList = [
{'imgUrl': 'images/发起群聊.png', 'name': '发起群聊'},
{'imgUrl': 'images/添加朋友.png', 'name': '添加朋友'},
{'imgUrl': 'images/扫一扫1.png', 'name': '扫一扫'},
{'imgUrl': 'images/收付款.png', 'name': '收付款'},
];
复制代码
然后介绍弹层,弹层 PopupMenuButton
实际上显示默认是一个按钮组件,只是在加入了 Dialog
,点击时会弹出弹窗层,多了这么一个功能而已
//导航
AppBar(
title: const Text("聊天"),
foregroundColor: Colors.black,
backgroundColor: const Color.fromRGBO(0xe1, 0xe1, 0xe1, 1),
elevation: 0, //去掉阴影
//导航右侧按钮组
actions: [
//外部container可以用来调整间距,不放到里面的Container
//是因为这个margin会增加点击区域,毕竟外面包了一层TextButton一样的东西
Container(
margin: const EdgeInsets.only(right: 10),
//使用 PopupMenuButton 来定义右侧点击弹层功能
child: PopupMenuButton(
//弹层实物位置,相对于当前组件的偏移
offset: const Offset(0, 56),
//我们看到的按钮的信息,组件给其默认添加点击事件
child: Container(
width: 40,
height: 40,
alignment: Alignment.center,
child: Image.asset("images/圆加.png", width: 20),
),
//返回内部组件信息列表,单行 item 使用 PopupMenuItem
//使用 .map<PopupMenuItem> 的原因可以动态生成多个 item
itemBuilder: (BuildContext context) {
return popList.map<PopupMenuItem>((item) {
return PopupMenuItem(
//水平布局,左侧图片,右侧问题,中间间隔使用 Sizebox即可
child: Row(
children: [
Image.asset(item['imgUrl'], width: 18),
const SizedBox(width: 10),
Text(item['name'],
style: const TextStyle(color: Colors.white)),
],
),
);
}).toList();
},
),
)
],
),
复制代码
仅仅这样发现,弹窗背景颜色不对,弹窗的背景我们需要在 MaterialApp
组件的 theme
属性中加入cardColor
才可以
MaterialApp(
//去掉debug自选
debugShowCheckedModeBanner: false,
//Android任务管理器界面title,可以设置称自己的app名字
title: "Flutter Demo",
theme: ThemeData(
//这个就是设置默认弹层的背景颜色
cardColor: const Color.fromRGBO(0x33, 0x33, 0x33, 0.8),
),
home: const HomePage()
);
复制代码
最后
快来试一下吧,越用越顺手