#星光不负 码向未来# 鸿蒙 ArkUI 小白笔记:从 0 到 1 搓个聊天列表(保姆级教程) 原创

大声喧哗小u伤
发布于 2025-10-22 11:12
浏览
1收藏

@[toc]

前言

嘿,小伙伴们!刚入门鸿蒙 ArkUI,是不是感觉“我是谁,我在哪,我要干什么”?别慌,今天我(一个和你一样的小白)就带大家用一份(我自个儿写的)Demo,来拆解一下怎么在鸿蒙上“搓”一个聊天列表。
#星光不负 码向未来# 鸿蒙 ArkUI 小白笔记:从 0 到 1 搓个聊天列表(保姆级教程)-鸿蒙开发者社区
不求精通,但求看懂!咱们的目标是:代码一句不改,知识点一个不落!

准备好了吗?发车!


第一站:开局与“状态”管理

#星光不负 码向未来# 鸿蒙 ArkUI 小白笔记:从 0 到 1 搓个聊天列表(保姆级教程)-鸿蒙开发者社区

首先,我们得有个“门面”。在 ArkUI 里,@Entry 就是告诉系统:“嘿,从这儿进!” @Component 则是定义一个“自定义组件”,你可以理解为咱们正在盖的“积木房子”。

然后,我们隆重请出 ArkUI 的“魔法师”—— @State。这玩意儿可厉害了,被它“点化”过的变量,一旦发生变化,UI 界面就会“Duang”一下自动刷新。

咱们这里定义了三个状态变量:

  1. keyword: 用来存搜索框里的字(虽然这个 Demo 里还没完全实现搜索联动,但坑先占上)。
  2. chatList: 咱们的“数据库”,存着原始的聊天数据。
  3. filteredList: 真正显示在界面上的列表。为啥要多一个?因为我们要根据 keyword 来“过滤”嘛!
@Entry
@Component
export struct ChatListDemo {
  aboutToAppear() {
    this.updateFiltered();
  }
  @State keyword: string = '';
  @State chatList: ChatItem[] = [
    new ChatItem(1, '张三', '最近项目进展怎么样?', '09:20', 2, '#FF6B6B'),
    new ChatItem(2, '李四', '好的,下午开会见。', '昨天', 0, '#4A90E2'),
    new ChatItem(3, '产品群', 'PRD已更新到v1.2,请查收。', '周一', 5, '#34C759'),
    new ChatItem(4, '技术交流群', '谁了解一下ArkUI最新特性?', '08:05', 0, '#FF9500'),
    new ChatItem(5, '王五', '下班一起打球?', '10:12', 1, '#AF52DE')
  ];

  @State filteredList: ChatItem[] = [];

第二站:数据“蓝图” (Class)

#星光不负 码向未来# 鸿蒙 ArkUI 小白笔记:从 0 到 1 搓个聊天列表(保姆级教程)-鸿蒙开发者社区

光有数据还不行,我们得告诉程序,咱们的“聊天数据”长啥样。class ChatItem 就是这个“蓝图”。它规定了每条聊天记录都必须有 idnamelastMessage 等属性。

这就是面向对象里的“建模”,说白了就是“丑话说在前头,你要存数据,必须按这个格式来”。

class ChatItem {
  id: number;
  name: string;
  lastMessage: string;
  time: string;
  unreadCount: number;
  color: string;

  constructor(id: number, name: string, lastMessage: string, time: string, unreadCount: number, color: string) {
    this.id = id;
    this.name = name;
    this.lastMessage = lastMessage;
    this.time = time;
    this.unreadCount = unreadCount;
    this.color = color;
  }
}

第三站:“开机自启”与“过滤神功”

aboutToAppear() 是一个“生命周期”函数。你可以理解为“演员准备登台前的那一刻”。组件马上要显示了,它就会被自动调用。

我们在这里调用了 this.updateFiltered(),目的就是在“开机”时,先把 chatList 里的所有数据显示出来。
#星光不负 码向未来# 鸿蒙 ArkUI 小白笔记:从 0 到 1 搓个聊天列表(保姆级教程)-鸿蒙开发者社区
updateFiltered() 则是我们的“过滤神功”。

  • 它先检查 this.keyword 是不是空的。
  • 如果是空的(!k),太好了,filteredList 直接“全盘复制” chatList
  • 如果不是空的,它就会用 JS/TS 祖传的 .filter() 方法,去 base (也就是 chatList) 里“筛”一遍,只留下 namelastMessage 包含关键词( k )的条目。

<!-- end list -->

  private updateFiltered() {
    const base = Array.isArray(this.chatList) ? this.chatList : [];
    const k = (this.keyword ?? '').trim();
    this.filteredList = !k ? base : base.filter(item => item.name.includes(k) || item.lastMessage.includes(k));
  }

第四站:build!开搭界面!

#星光不负 码向未来# 鸿蒙 ArkUI 小白笔记:从 0 到 1 搓个聊天列表(保姆级教程)-鸿蒙开发者社区

build() 函数是重头戏!它就是我们 UI 的“总设计师”。ArkUI 是“声明式 UI”,意思就是:你别管怎么画,你只要告诉我“长啥样”就行

我们先用一个 Column()(垂直布局),把“顶部标题区”和“聊天列表区”从上到下“码”起来。

  build() {
    Column() {

第五站:精致的“顶栏” (AppBar)

#星光不负 码向未来# 鸿蒙 ArkUI 小白笔记:从 0 到 1 搓个聊天列表(保姆级教程)-鸿蒙开发者社区

在第一个 Column 里,我们再放一个 Column 来装“顶部标题区”(包含标题和搜索框)。

首先,用 Row()(水平布局)来做标题栏。

  • 中间的 Text('消息') 被包在一个 Row 里,并且设置了 .layoutWeight(1).justifyContent(FlexAlign.Center)
    • layoutWeight(1) 是个神器!意思是:“在这一行里,你(中间的标题)能占多宽占多宽,把其他兄弟挤到边上去!”
    • justifyContent(FlexAlign.Center) 则是让标题在它占据的广阔空间里“居中”。
  • 右侧的 Button(那个“+”号)就老实待在它该在的地方。

<!-- end list -->

      // 顶部标题区:大标题 + 次要操作(新聊天)
      Column() {
        // 顶部 AppBar 风格
        Row()
        {

          // 中间标题
          Row() {
            Text('消息')
              .fontSize(22)
              .fontWeight(FontWeight.Bold)
              .fontColor('#111111')
          }
          .layoutWeight(1)
          .justifyContent(FlexAlign.Center)

          // 右侧操作:新聊天(改为图标按钮)
          Button() {
            // 使用简单加号图标符号
            Text('+')
              .fontSize(20)
              .fontWeight(FontWeight.Bold)
              .fontColor('#FFFFFF')
          }
          .type(ButtonType.Circle)
          .width(36)
          .height(36)
          .backgroundColor('#0D9FFB')
        }
        .height(56)
        .width('100%')
        .backgroundColor('#F8F9FA')
        .padding({ left: 16, right: 16 })

第六站:搜索框登场

#星光不负 码向未来# 鸿蒙 ArkUI 小白笔记:从 0 到 1 搓个聊天列表(保姆级教程)-鸿蒙开发者社区

在“标题栏” Row 的下面,还是在“顶部标题区” Column 内部,我们再放一个 Row,用来装 TextInput(搜索框)。

这里我们让它 .layoutWeight(1) 占满整行,并用 .borderRadius(20) 把它变成圆角矩形。它就是我们未来实现搜索功能的“入口”!

        // 标题下方放置搜索框,提高层次感
        Row() {
          TextInput({ placeholder: '搜索联系人或消息内容' })
            .height(40)
            .border({ width: 1, color: '#E5E5EA' })
            .borderRadius(20)
            .padding({ left: 12, right: 12 })
            .layoutWeight(1)
        }
        .padding({ top: 8, left: 16, right: 16, bottom: 8 })
      }

第七站:列表“本体” (List & ForEach)

#星光不负 码向未来# 鸿蒙 ArkUI 小白笔记:从 0 到 1 搓个聊天列表(保姆级教程)-鸿蒙开发者社区

“顶部标题区” Column 结束后,轮到“聊天列表区” List 登场了。

List 是专门用来显示长列表的(有性能优化哦)。
ForEach 则是“循环器”,它干的活就是:

  1. 遍历 this.filteredList(还记得吗?被 @State 点化过的那个)。
  2. 每遍历到一条 item 数据,就创建一个 ListItem
  3. ListItem 里面干啥呢?调用 this.renderChatItem(item)
  4. item.id.toString() 是给每一项一个“身份证”(key),这样 ArkUI 在刷新列表时能精确知道谁是谁,效率更高。

最后,我们又用了 .layoutWeight(1),让列表占满“顶部标题区”以外的 所有 剩余垂直空间。

      // 注:搜索框已移动到标题区下方,这里删除重复输入框


      // 聊天列表
      List() {
        ForEach(this.filteredList, (item: ChatItem, index: number) => {
          ListItem() {
            this.renderChatItem(item)
          }
        }, (item: ChatItem, index: number) => item.id.toString())
      }
      .height('100%')
      .width('100%')
      .layoutWeight(1)
      .divider({ strokeWidth: 0.5, color: '#F2F2F7' })
      .edgeEffect(EdgeEffect.None)
      .margin({ top: 8 })
    }
    .height('100%')
    .backgroundColor('#FFFFFF')
  }

第八站:可复用的“积木” (@Builder)

#星光不负 码向未来# 鸿蒙 ArkUI 小白笔记:从 0 到 1 搓个聊天列表(保姆级教程)-鸿蒙开发者社区

build 函数是不是快“爆炸”了?太乱了!

ArkUI 提供了 @Builder 装饰器,让我们能“封装”一小块 UI。它就像一个“返回 UI 的函数”或者“UI 积木”,让 build 函数更清爽。

我们先看这个 renderAvatar,它专门负责画“头像”。它用 Stack()(堆叠布局)把一个单字 Text 放在一个彩色圆圈 Stack正中间

  @Builder
  private renderAvatar(item: ChatItem) {
    // 使用首字作为简易头像
    Stack() {
      Text(item.name.substring(0, 1))
        .fontSize(18)
        .fontColor('#FFFFFF')
        .align(Alignment.Center)
    }
    .width(48)
    .height(48)
    .backgroundColor(item.color)
    .borderRadius(24)
    .margin({ right: 12 })
  }

第九站:“积木”拼装 (renderChatItem)

#星光不负 码向未来# 鸿蒙 ArkUI 小白笔记:从 0 到 1 搓个聊天列表(保姆级教程)-鸿蒙开发者社区
现在我们看 renderChatItem 这个“大积木”。

  1. 它先用 Row 把“头像区”和“内容区”横向摆放。
  2. 头像区:这里用了 Stack() 布局。
    • 底层是 this.renderAvatar(item)(刚刚造的“头像积木”)。
    • 上层是 if (item.unreadCount > 0)(判断是否有未读消息)。
    • 如果有,就在上面“堆”一个红点 Row(包含 Text)。
    • .position({ x: 34, y: -4 }) 是点睛之笔!它用“绝对定位”把红点“精确”地““糊””在了头像的右上角。
  3. 内容区:用 Column 纵向摆放“第一行(名字+时间)”和“第二行(消息)”。
    • 第一行 Row 使用了 justifyContent(FlexAlign.SpaceBetween),让“名字”和“时间”自动“两端对齐”。
    • 第二行 Text 简单显示消息,并用 textOverflow 处理了“超出部分显示省略号(…)”。

<!-- end list -->

  @Builder
  private renderChatItem(item: ChatItem) {
    Row() {
      // 头像(带未读角标)
      Stack() {
        this.renderAvatar(item)
        if (item.unreadCount > 0) {
          Row() {
            Text(item.unreadCount.toString())
              .fontSize(10)
              .fontColor('#FFFFFF')
              .backgroundColor('#FF3B30')
              .borderRadius(8)
              .padding({ left: 5, right: 5, top: 2, bottom: 2 })
          }
          .position({ x: 34, y: -4 })
        }
      }

      // 内容
      Column() {
        // 顶部一行:name 和 time 两端对齐
        Row()
        {

          Text(item.name)
            .fontSize(16)
            .fontWeight(FontWeight.Medium)
            .fontColor('#111111')
            .layoutWeight(1)
            .textAlign(TextAlign.Start)
          Text(item.time)
            .fontSize(12)
            .fontColor('#8E8E93')
            .textAlign(TextAlign.End)
        }
        .width('100%')
        .justifyContent(FlexAlign.SpaceBetween)

        // 第二行:lastMessage 居左
        Text(item.lastMessage)
          .fontSize(14)
          .fontColor('#8E8E93')
          .width('100%')
          .textAlign(TextAlign.Start)
          .maxLines(1)
          .textOverflow({ overflow: TextOverflow.Ellipsis })
      }
      .padding({ left: 12, right: 12 })
      .width('75%')
    }
    .height(72)
    .padding({ left: 16, right: 16 })
    .backgroundColor('#FFFFFF')
    .onClick(() => {
      // 点击条目,可跳转到聊天详情页(此Demo暂不实现详情)
      // 可扩展:router.pushUrl({ url: 'pages/ChatDetail', params: { id: item.id.toString() } })
      console.info(`Open chat with ${item.name}`)
    })
  }
} // 别忘了,这是 ChatListDemo struct 的结尾 }

收工总结!

呼… 一口气看完了!我们来总结一下今天学到的“黑话”:

  1. @Entry / @Component:组件的“户口本”。
  2. @State:能让 UI 自动刷新的“魔法”变量。
  3. build():UI“总设计师”,在这里“声明”你的界面长啥样。
  4. Column / Row / Stack:布局三剑客(垂直、水平、堆叠)。
  5. .layoutWeight(1):“占满剩余空间”的霸道属性。
  6. List / ForEach:渲染列表的黄金搭档。
  7. @Builder:可复用的“UI 积木”,让代码更整洁。
  8. 生命周期 (如 aboutToAppear):在特定时机(如“即将显示”)自动执行的函数。

怎么样,是不是感觉 ArkUI 也没那么“劝退”?它就是用各种组件和布局,像搭积木一样把界面“拼”出来,我们来看看预览器中的效果图:
#星光不负 码向未来# 鸿蒙 ArkUI 小白笔记:从 0 到 1 搓个聊天列表(保姆级教程)-鸿蒙开发者社区
怎么样,是不是很有成就感!赶紧动手试试吧!跟着我的笔记操作,你也能写出来主流的聊天列表!如果游刃有余的同学,可以尝试自己实现一下聊天详情页面。

好了,到站了,同学,别睡了,快下车!下次再见,哈哈~

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
2
收藏 1
回复
举报
2条回复
按时间正序
/
按时间倒序
锦绣河山醉清风
锦绣河山醉清风

非常不错,幽默风趣间就学会了。。。赞一个

回复
2025-10-22 11:22:10
全栈若城
全栈若城

6666~~~


回复
2025-10-22 11:29:39
回复
    相关推荐