flutter-imitation WeChat project combat four (chat list, list pop-up layer)

foreword

The network request has been introduced before. Here we mainly introduce the construction of the chat list, and scan the bullet layer there. The bullet layer mainly uses system controls.PopupMenuButton

ps : If you want to customize the pop-up window yourself, there is an introduction to the customization of Dialog.

Source address

Custom dialog pop-up layer address

chat list

According to the previous introduction, it is actually ListView.buildervery easy to implement the chat list. Here, he mainly introduces the ListTileclass , which can at least reduce some code nesting.

First look at the effect

image.png

The code looks like this:

//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)),
  );
}
复制代码

ListTileThere is no underline by default. If you want to underline, just wrap it with a layer, as shown below

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))),
      ],
    )
  ],
);
复制代码

chat data

Requested by the httpframework , and then translated step by step into the class we use

//这里主要简介数据获取,网络失败后的 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;
}
复制代码

ChatListDataThe definition of the class is as follows. Since I didn't see dartreflection related, this part can only be written by myself (unlike JavaScriptno classclass restriction, which can be directly assigned and called)

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']);
  }
}
复制代码

Sweep the bomb layer

Click the plus sign in the upper right corner of the WeChat chat page, and a click interface for scanning will pop up, and see the effect first.

image.png

First declare the data information of the pop-up layer on the right, which is directly used here. MapThe bytes can also be placed in a class, as shown below

List popList = [
  {'imgUrl': 'images/发起群聊.png', 'name': '发起群聊'},
  {'imgUrl': 'images/添加朋友.png', 'name': '添加朋友'},
  {'imgUrl': 'images/扫一扫1.png', 'name': '扫一扫'},
  {'imgUrl': 'images/收付款.png', 'name': '收付款'},
];
复制代码

Then introduce the pop-up layer. The pop-up layer PopupMenuButtonactually shows that it is a button component by default, but when it is added Dialog, the pop-up layer will pop up when you click it, and there is such a function.

//导航
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();
        },
      ),
    )
  ],
),
复制代码

It is only found that the background color of the pop-up window is wrong. We need to add the background of the pop-up window MaterialAppto the themeproperties of the cardColorcomponent .

MaterialApp(
  //去掉debug自选
  debugShowCheckedModeBanner: false,
  //Android任务管理器界面title,可以设置称自己的app名字
  title: "Flutter Demo",
  theme: ThemeData(
    //这个就是设置默认弹层的背景颜色
    cardColor: const Color.fromRGBO(0x33, 0x33, 0x33, 0.8),
  ),
  home: const HomePage()
);
复制代码

At last

Come and try it, the more you use it, the easier it is

Guess you like

Origin juejin.im/post/7087422451893665828