1# 使用Badge组件完成聊天未读消息数量显示功能 2 3## 场景介绍 4开发者在业务开发过程中,需要通过角标的形式对用户的通知信息进行提示,并展示具体数量,如聊天页面中,用户可以看到与其他聊天对象的未读消息数量。本文就从聊天页面未读消息数量展示场景出发,介绍OpenHarmony中如何使用Badge组件实现该场景。 5 6## 效果呈现 7 8如下动图所示: 9 10 11 12## 环境要求 13本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发: 14- IDE: DevEco Studio 4.0 Release 15- SDK: Ohos_sdk_public 4.0.10.13 (API Version 10 Release) 16 17## 实现原理 18 19本例涉及的关键特性以及实现方案如下: 20 21- 完成聊天列表子组件创建,其中头像部分放入容器组件Badge中。 22- 封装聊天列表子组件类,并引用@Observed装饰器,保证类中未读聊天信息数量数据状态可被观察。 23- 最后,通过ForEach组件完成聊天聊表的内容渲染。 24 25## 开发步骤 26 271. 聊天列表组件,包含三部分:聊天对象的头像,聊天对象昵称,用户聊天记录最后一条详情。其中未读聊天信息数量显示在头像的右上角。因此头像部分需要放入容器组件Badge中。Badge中需要设置消息数量,提示显示位置,最大消息数量,显示样式。 28 聊天列表组件代码如下: 29 ```ts 30 @Component 31 struct MyComposeTitleBar { 32 @ObjectLink simplifyChatInfo: SimplifyChatInfo; 33 34 build() { 35 Row() { 36 Badge({ 37 count: this.simplifyChatInfo.notReadCount, 38 maxCount: 99, 39 position:BadgePosition.RightTop, 40 style: { badgeSize: 15, badgeColor: '#FA2A2D' } 41 }) { 42 Image($r('app.media.ic_user_portrait')).width(50).height(50) 43 } 44 .width(50) 45 .height(50) 46 .margin({ bottom: 4 }) 47 48 Row() { 49 Column() { 50 Text(this.simplifyChatInfo.chaterNickName) 51 .fontSize(36) 52 .fontWeight(FontWeight.Bold) 53 .width("70%") 54 .textOverflow({ overflow: TextOverflow.Clip }) 55 .maxLines(1) 56 Text(this.simplifyChatInfo.details) 57 .fontSize(24) 58 .fontWeight(FontWeight.Normal) 59 .width("90%") 60 .textOverflow({ overflow: TextOverflow.Ellipsis }) 61 .maxLines(1) 62 Divider().color(Color.Gray).strokeWidth(1).lineCap(LineCapStyle.Round) 63 }.alignItems(HorizontalAlign.Start) 64 }.margin({left:15}) 65 }.backgroundColor('#d7ffffff') 66 } 67 } 68 ``` 69 70 713. 创建用于表征聊天列表数据的类,该类需要被@Observed修饰,是的类中数据可以被Badge组件观察。 72 73 聊天列表数据类代码块: 74 75 ```ts 76 @Observed 77 class SimplifyChatInfo { 78 public chaterNickName: string; 79 public details: string; 80 //未读消息数量 81 public notReadCount: number; 82 83 constructor(chaterNickName: string, details: string, notReadCount: number) { 84 this.chaterNickName = chaterNickName 85 this.details = details 86 this.notReadCount = notReadCount 87 } 88 } 89 ``` 90 913. 最后通过ForEach完成数据渲染。 92 93 ```ts 94 List() { 95 ForEach(this.chatArr, (item: SimplifyChatInfo) => { 96 ListItem() { 97 MyComposeTitleBar({ simplifyChatInfo: item }) 98 } 99 }) 100 } 101 ``` 102 103 104## 完整实例 105 106完整实例代码如下: 107 108```ts 109@Entry 110@Component 111export default struct HarmonyChat { 112 @State chatArr: Array<SimplifyChatInfo> = [] 113 scroller: Scroller = new Scroller() 114 115 build() { 116 Row() { 117 Column() { 118 Text('聊天列表页').fontSize(30).fontWeight(FontWeight.Bold).height("20%") 119 .margin({ 120 top: 16, 121 bottom: 16 122 }) 123 124 Scroll(this.scroller) { 125 Column() { 126 List() { 127 ForEach(this.chatArr, (item: SimplifyChatInfo) => { 128 ListItem() { 129 MyComposeTitleBar({ simplifyChatInfo: item }) 130 } 131 }) 132 } 133 }.height("80%") 134 } 135 136 }.width('100%') 137 }.alignItems(VerticalAlign.Center) 138 .backgroundColor("#f1f3f5") 139 .height('100%') 140 } 141 142 aboutToAppear() { 143 //模拟数据 144 for (let i = 0; i < 3; i++) { 145 let sci: SimplifyChatInfo = new SimplifyChatInfo( 146 "nickName" + 111 * i, 147 `你好!` + "nickName" + 111 * i + "!!!", 148 0 149 ) 150 this.chatArr.push(sci) 151 } 152 setInterval(() => { 153 let date = new Date() 154 let second = date.getSeconds() 155 this.chatArr[second%3].notReadCount = this.chatArr[second%3].notReadCount + 1 156 }, 1000) 157 } 158} 159 160@Component 161struct MyComposeTitleBar { 162 @ObjectLink simplifyChatInfo: SimplifyChatInfo; 163 164 build() { 165 Row() { 166 Badge({ 167 count: this.simplifyChatInfo.notReadCount, 168 maxCount: 99, 169 position:BadgePosition.RightTop, 170 style: { badgeSize: 20, badgeColor: '#FA2A2D',fontSize:15 } 171 }) { 172 Image($r('app.media.ic_user_portrait')).width(50).height(50) 173 } 174 .width(50) 175 .height(50) 176 .margin({ bottom: 4 }) 177 178 Row() { 179 Column() { 180 Text(this.simplifyChatInfo.chaterNickName) 181 .fontSize(36) 182 .fontWeight(FontWeight.Bold) 183 .width("70%") 184 .textOverflow({ overflow: TextOverflow.Clip }) 185 .maxLines(1) 186 Text(this.simplifyChatInfo.details) 187 .fontSize(24) 188 .fontWeight(FontWeight.Normal) 189 .width("90%") 190 .textOverflow({ overflow: TextOverflow.Ellipsis }) 191 .maxLines(1) 192 Divider().color(Color.Gray).strokeWidth(1).lineCap(LineCapStyle.Round) 193 }.alignItems(HorizontalAlign.Start) 194 }.margin({left:15}) 195 }.backgroundColor('#d7ffffff') 196 } 197} 198 199 200@Observed 201class SimplifyChatInfo { 202 public chaterNickName: string; 203 public details: string; 204 //未读消息数量 205 public notReadCount: number; 206 207 constructor(chaterNickName: string, details: string, notReadCount: number) { 208 this.chaterNickName = chaterNickName 209 this.details = details 210 this.notReadCount = notReadCount 211 } 212} 213``` 214 215## 参考 216 217[Badge](../application-dev/reference/apis-arkui/arkui-ts/ts-container-badge.md) 218 219[@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化](../application-dev/quick-start/arkts-observed-and-objectlink.md) 220 221[ForEach:循环渲染](../application-dev/quick-start/arkts-rendering-control-foreach.md) 222 223 224 225