如何使用List组件实现聊天列表功能
==================

#### 问题现象

聊天列表是即时通讯中比较重要的功能，如何使用List组件实现聊天列表功能？

#### 背景知识

[List](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-layout-development-create-list)组件应用于多种场景，如商品展示、聊天页面、发票页面等。[@Watch](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-watch)应用于对状态变量的监听，如果需要关注某个状态变量的值是否改变，可以使用@Watch为状态变量设置回调函数。

#### 解决方案

*   **场景一**：**收到新数据时从底部开始显示**。
    *   **实现原理：** 使用[@Watch](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-watch)监听数据源的变化，当数据源变化时，若List不在最底部显示，则将List自动滚到最底部。
    *   **示例代码：**
        
        @Component
        struct Chat {
          _// 这个列表代表聊天内容，每次发送和接收消息时，把聊天内容加入这个列表。当监听到列表发生变化时，执行函数scrollerBottom，把list滑动到最底部。_
          @Prop @Watch('scrollerBottom') list: string\[\] = \[\];
          scroller: Scroller = new Scroller();
        
          scrollerBottom() {
            this.scroller.scrollEdge(Edge.Bottom);
          }
        
          build() {
            _// initialIndex代表列表生成时，从第几个索引值开始展示，选择最后一个索引值，就实现了显示最底部的消息。scroller代表绑定滚动事件，配合List监听，实现发送和接收消息，都能滚动到最底部。_
            List({ initialIndex: this.list.length - 1, scroller: this.scroller }) {
              ForEach(this.list, (item: string) => {
                ListItem() {
                  Text(item)
                    .width('100%')
                    .margin(5)
                    .textAlign(TextAlign.Center)
                }
              });
            }
            .width('100%')
            .height('100%');
          }
        }
        
        @Entry
        @Component
        struct ListChat {
          @State message: string\[\] = \[\];
          count: number = 0;
        
          build() {
            Column(){
              Column() {
                Chat({ list: this.message })
                  .width('90%')
                  .borderRadius(12)
                  .backgroundColor('#F1F3F5');
                Button('新增消息')
                  .onClick(() => {
                    this.message.push('新消息' + (this.count++).toString());
                  })
                  .width('90%')
                  .margin({ top: 20 })
                  .backgroundColor('#0A59F7');
              }
              .height('50%')
              .width('100%')
            }
            .justifyContent(FlexAlign.Center).height('100%')
            .alignItems(HorizontalAlign.Center);
          }
        }
        
    *   **效果图：**
        
        ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/ed/v3/J-_5ct6UTX6zSbMg1ZTeng/zh-cn_image_0000002658846237.png?HW-CC-KV=V1&HW-CC-Date=20260709T133954Z&HW-CC-Expire=86400&HW-CC-Sign=C3359EFD3E24D93334F68404E7635761B015914F22A0F28350BB8901B4597A10 "点击放大")
        
*   **场景二**：**消息列表从底部开始加载，点击按钮回到最新位置**。
    *   **实现原理：** 将List组件的[stackFromEnd](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-list#stackfromend19)属性设置为true可以实现列表从底部开始布局加载，给[scrollEdge](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-scroll#scrolledge)绑定List底部边界，实现跳转回到最新位置。
        
        ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/db/v3/M859cH-URXmig28lzdTJcA/notice_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260709T133954Z&HW-CC-Expire=86400&HW-CC-Sign=FABF839862C458325360D13B5D4EFA08CE66A5289EAA1F49E83A01433DD2FEAA)
        
        属性stackFromEnd从API version 19开始支持使用。
        
    *   **示例代码：**
        
        @Entry
        @Component
        struct ListBottom {
          @State listContent: Array<string> = \['旧消息'\];
          listScroller: ListScroller = new ListScroller();
        
          build() {
            Column() {
              List({ space: 10, scroller: this.listScroller }) {
                ForEach(this.listContent, (value: string) => {
                  ListItem() {
                    Text(value);
                  }
                  .width('90%')
                  .height(200)
                  .border({
                    width: 0,
                    radius: 20,
                  })
                  .backgroundColor(Color.White);
                });
              }
              .width('100%')
              .height('82%')
              .stackFromEnd(true) _// 设置为true表示列表从底部开始布局_
              .alignListItem(ListItemAlign.Center)
              .scrollBar(BarState.Off)
        
              Column() {
                Button('新增消息')
                  .onClick(() => {
                    this.listContent.push('新消息' + this.listContent.length.toString());
                  })
                  .width('100%')
                  .margin({ top:8 ,bottom:5})
        
                Button('回到最新位置')
                  .onClick(() => {
                    this.listScroller.scrollEdge(Edge.Bottom); _// 将列表滚动到底部边界位置_
                  })
                  .width('100%')
                  .margin({top:8,bottom:20})
              }
              .width('90%')
              .justifyContent(FlexAlign.SpaceAround);
            }
            .expandSafeArea(\[SafeAreaType.SYSTEM\], \[SafeAreaEdge.BOTTOM,SafeAreaEdge.TOP\])
            .backgroundColor('#F1F3F5')
            .width('100%')
            .height('100%')
            .justifyContent(FlexAlign.SpaceBetween);
          }
        }
        
    *   **效果图：**
        
        ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/54/v3/sHiaTu25TnaS9EUBS-KNpQ/zh-cn_image_0000002628766878.png?HW-CC-KV=V1&HW-CC-Date=20260709T133954Z&HW-CC-Expire=86400&HW-CC-Sign=C355BEA028DBBE7867503184DCD312D816058A70C5A5DC4E0E1839FBB0372231 "点击放大")
        

#### 常见FAQ

Q：如何解决插入图片发生闪烁问题？

A：可以使用syncLoad属性解决，具体可以参考[社区解决方案](https://developer.huawei.com/consumer/cn/blog/topic/03154617617506006)。