# 一多开å‘实例(çŸä¿¡ï¼‰ æœ¬ç« ä»Žç³»ç»Ÿé¢„ç½®çš„åº”ç”¨ä¸ï¼Œé€‰æ‹©çŸä¿¡åº”用作为典型的案例,从页é¢å¼€å‘和工程结构的角度,介ç»"一多"的具体实践。系统的产å“å½¢æ€åœ¨ä¸æ–丰富ä¸ï¼Œå½“å‰ä¸»è¦æœ‰é»˜è®¤è®¾å¤‡å’Œå¹³æ¿ä¸¤ç§äº§å“å½¢æ€ï¼Œæœ¬ç« 的具体实践也将围绕这两ç§äº§å“å½¢æ€å±•开。 ## 概览 çŸä¿¡æ˜¯ç³»ç»Ÿä¸é¢„置的应用,主è¦åŒ…å«ä¿¡æ¯æŸ¥çœ‹ã€å‘é€çŸä¿¡ã€æŽ¥æ”¶çŸä¿¡ã€çŸä¿¡é€è¾¾æŠ¥å‘Šã€åˆ 除çŸä¿¡ç‰åŠŸèƒ½ã€‚åœ¨ä¸åŒç±»åž‹è®¾å¤‡ä¸Šï¼ŒçŸä¿¡åº”用的功能完全相åŒï¼Œæ•…çŸä¿¡åº”用适åˆä½¿ç”¨[部署模型A](introduction.md#部署模型)(å³ï¼šä¸åŒç±»åž‹çš„设备上安装è¿è¡Œç›¸åŒçš„HAP或HAP组åˆï¼‰ã€‚ 本案例ä¸ï¼Œåœ¨ä¼šè¯è¯¦æƒ…页é¢åˆ©ç”¨[æ–¹èˆŸå¼€å‘æ¡†æž¶](introduction.md#æ–¹èˆŸå¼€å‘æ¡†æž¶)æä¾›çš„“一多â€èƒ½åŠ›ï¼Œç”¨ä¸€å¥—ä»£ç åŒæ—¶é€‚é…默认设备和平æ¿ã€‚ ### 工程结构 çŸä¿¡åº”用的工程结构如下图所示,当å‰è¯¥åº”用的功能较少,所以直接使用了DevEco Studio创建出的默认工程结构。具体采用何ç§å½¢å¼çš„工程结构,并ä¸å½±å“应用的开å‘。但是使用推è的工程结构,目录结构更清晰,拓展性也更好。 çŸä¿¡åº”用UI相关的逻辑集ä¸åœ¨viewså’Œpagesä¸¤ä¸ªç›®å½•ï¼Œåˆ†åˆ«å˜æ”¾å…¬å…±ç»„ä»¶åŠé¡µé¢ã€‚当å‰çŸä¿¡åº”用主è¦åŒ…å«å¦‚下页é¢ï¼š - ä¿¡æ¯åˆ—表页é¢ï¼šé¦–页,展示信æ¯åˆ—表。 - 通知信æ¯åˆ—表页é¢ï¼šå°†é€šçŸ¥ç±»ä¿¡æ¯é›†ä¸åœ¨ä¸€èµ·å±•示,与信æ¯åˆ—表页é¢ç±»ä¼¼ã€‚ - 会è¯è¯¦æƒ…页é¢ï¼šå±•示与æŸè”系人的所有信æ¯å¾€æ¥ã€‚ - 报告详情页é¢ï¼šä¿¡æ¯å‘é€æŠ¥å‘Šçš„è¯¦æƒ…é¡µé¢ã€‚ - 设置页é¢ï¼šæ¶ˆæ¯è®¾ç½®é¡µé¢ï¼Œå¦‚是å¦å±•示é€è¾¾æŠ¥å‘Šç‰ã€‚ ``` /Mms/ ├── doc # 资料 ├── entry │ └── src │ └── main │ ├── resources # 资æºé…ç½®æ–‡ä»¶å˜æ”¾ç›®å½• │ ├── config.json # 全局é…置文件 │ └── ets # ets代ç 目录 │ ├── ServiceAbility # åŽå°å¸¸é©»æœåŠ¡ │ └── default # 业务代ç 目录 │ ├── data # 自定义数æ®ç±»åž‹ │ ├── model # 对接数æ®åº“ │ ├── pages # æ‰€æœ‰é¡µé¢ â”‚ │ ├── conversation # 会è¯è¯¦æƒ…é¡µé¢ â”‚ │ ├── conversationlist # ä¿¡æ¯åˆ—è¡¨é¡µé¢ â”‚ │ ├── index # åˆå§‹é¡µé¢ │ │ ├── info_msg # 通知信æ¯åˆ—è¡¨é¡µé¢ â”‚ │ ├── query_report # æŠ¥å‘Šè¯¦æƒ…é¡µé¢ â”‚ │ └── settings # è®¾ç½®é¡µé¢ â”‚ ├── service # 业务逻辑 │ ├── utils # 工具类 │ ├── views # 自定义组件 │ └── app.ets # 应用生命周期 ├── signs # ç¾å └── LICENSE ``` çŸä¿¡åº”用在开å‘阶段,采用了一层工程结构。由于功能较为简å•,所以并没有规划共用的featureå’Œcommon目录,仅采用了一层product目录。 - 业务形æ€å±‚(product) 该目录采用DevEco Studio工程默认创建的entry目录,开å‘è€…å¯æ ¹æ®éœ€è¦åœ¨åˆ›å»ºModule时自行更改该目录å。ä¸åŒäº§å“å½¢æ€ï¼Œç¼–译出相åŒçš„çŸä¿¡HAP。 ## 会è¯è¯¦æƒ…é¡µé¢ ### 页é¢ç»“æž„ | 默认设备 | å¹³æ¿ | | ---------------------------------------- | ---------------------------------------- | |  |  | 会è¯è¯¦æƒ…页é¢åœ¨é»˜è®¤è®¾å¤‡å’Œå¹³æ¿ä¸Šçš„æ ·å¼å¦‚上图所示,会è¯è¯¦æƒ…页é¢å¯ä»¥åˆ’分为三个部分: | 页é¢ç»„æˆ | ä»‹ç» | | ----- | ---------------------------------------- | | é¡¶éƒ¨æ ‡é¢˜æ |  | | ä¿¡æ¯åˆ—表 |  | | 底部输入æ |  | æŽ¥ä¸‹æ¥æˆ‘们详细介ç»å„部分的实现。 > **说明:** > 为了方便ç†è§£ï¼Œæˆ‘们对会è¯è¯¦æƒ…页é¢åšäº†ä¸€å®šçš„精简,本å°èЂ仅介ç»ä¼šè¯è¯¦æƒ…页颿œ€åŸºç¡€çš„实现。 ### é¡¶éƒ¨æ ‡é¢˜æ | 默认设备 | å¹³æ¿ | | ---------------------------------------- | ---------------------------------------- | |  |  | é¡¶éƒ¨æ ‡é¢˜æ æ˜¯ä¸€ä¸ªç®€å•的行布局,包å«è¿”å›žå›¾æ ‡ã€è”系人头åƒã€è”系人姓åå’Œå·ç ã€æ‹¨å·å›¾æ ‡ã€è®¾ç½®å›¾æ ‡å…±5ä¸ªå…ƒç´ ã€‚å…¶ä¸ï¼Œè”系人姓åå’Œå·ç ä»¥åˆ—å¸ƒå±€çš„å½¢å¼æ”¾åœ¨ä¸€èµ·ã€‚ 在默认设备和平æ¿ä¸Šï¼Œé¡¶éƒ¨æ ‡é¢˜æ 的组件结构是相åŒçš„,仅è”系人姓åå’Œå·ç 与拨å·å›¾æ ‡çš„é—´è·ä¸åŒã€‚å›žé¡¾æ–¹èˆŸå¼€å‘æ¡†æž¶ä¸€å¤šèƒ½åЛ介ç»ï¼Œè¿™ä¸ªåœºæ™¯å¯ä»¥å€ŸåŠ©Blank组件使用拉伸能力。 我们先实现è”系人姓åå’Œå·ç ,用Flex组件作为父容器,其包å«ä¸¤ä¸ªTextåç»„ä»¶ï¼Œåˆ†åˆ«ç”¨äºŽå˜æ”¾è”系人姓åå’Œå·ç 。Flex组件的属性设置如下: - direction: FlexDirection.Column:å组件在Flexå®¹å™¨ä¸Šä»¥åˆ—çš„æ–¹å¼æŽ’å¸ƒï¼Œå³ä¸»è½´æ˜¯åž‚ç›´æ–¹å‘。 - justifyContent: FlexAlign.Center:å组件在Flex容器主轴(垂直方å‘)上居ä¸å¯¹é½ã€‚ - alignItems: ItemAlign.Start:å组件在Flex容器交å‰è½´ï¼ˆæ°´å¹³æ–¹å‘)上首部对é½ã€‚ å¯ä»¥æŸ¥çœ‹[Flex组件](../../reference/apis-arkui/arkui-ts/ts-container-flex.md)åŠ[Text组件](../../reference/apis-arkui/arkui-ts/ts-basic-components-text.md)了解这两个组件å„个属性的å«ä¹‰åŠè¯¦ç»†ç”¨æ³•。 | 默认设备 | å¹³æ¿ | | ---------------------------------------- | ---------------------------------------- | |  |  | ```ts @Entry @Component struct TopArea { build() { Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Start}) { Text('å¼ ä¸‰').fontSize(16).fontColor("#182431") Text('+123 4567 8901').fontSize(14).fontColor("#66182431") } } } ``` æŽ¥ä¸‹æ¥æˆ‘们通过width属性和heightå±žæ€§è®¾ç½®å››ä¸ªå›¾æ ‡çš„å®½é«˜ï¼ˆè¯¦è§[尺寸设置](../../reference/apis-arkui/arkui-ts/ts-universal-attributes-size.md)),并将它们与è”系人姓å和电è¯ä»¥åŠBlank组件一起放到Flex父容器ä¸ã€‚ä¸ºäº†ä¾¿äºŽæŸ¥çœ‹æ•ˆæžœï¼Œå¯¹é¡¶éƒ¨æ ‡é¢˜æ 设置了淡è“色的背景色。 | 默认设备 | å¹³æ¿ | | ---------------------------------------- | ---------------------------------------- | |  |  | ```ts @Entry @Component struct TopArea { build() { Flex({ alignItems: ItemAlign.Center }) { Image($r('app.media.back')) //在应用的resources/base/media目录放置å为backçš„èµ„æºæ–‡ä»¶ .width(24) .height(24) Image($r('app.media.contact')) //在应用的resources/base/media目录放置å为contactçš„èµ„æºæ–‡ä»¶ .width(40) .height(40) Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Start}) { Text('å¼ ä¸‰').fontSize(16).fontColor("#182431") Text('+123 4567 8901').fontSize(14).fontColor("#66182431") } Blank() // 拉伸能力 Image($r("app.media.phone")) //在应用的resources/base/media目录放置å为phoneçš„èµ„æºæ–‡ä»¶ .width(24) .height(24) Image($r('app.media.dots')) //在应用的resources/base/media目录放置å为dotsçš„èµ„æºæ–‡ä»¶ .width(24) .height(24) } .width('100%') .height(56) .backgroundColor('#87CEFA') // é¡¶éƒ¨æ ‡é¢˜æ èƒŒæ™¯è‰²ï¼Œä»…ç”¨äºŽå¼€å‘æµ‹è¯• } } ``` 当剿 ‡é¢˜æ ä¸å组件的布局åŒé¢„期还有些差异,接下æ¥é€šè¿‡margin属性,设置å„ä¸ªå…ƒç´ çš„å·¦å³é—´è·ï¼ˆè¯¦è§[尺寸设置](../../reference/apis-arkui/arkui-ts/ts-universal-attributes-size.md))。如下图所示,最终顶部工具æ 在默认设备和平æ¿ä¸Šéƒ½å¯ä»¥è¾¾åˆ°é¢„期显示效果。 | 默认设备 | å¹³æ¿ | | ---------------------------------------- | ---------------------------------------- | |  |  | ```ts @Entry @Component struct TopArea { build() { Flex({ alignItems: ItemAlign.Center }) { Image($r('app.media.back')) //在应用的resources/base/media目录放置å为backçš„èµ„æºæ–‡ä»¶ .width(24) .height(24) .margin({ left:24 }) // è®¾ç½®é—´è· Image($r('app.media.contact')) //在应用的resources/base/media目录放置å为contactçš„èµ„æºæ–‡ä»¶ .width(40) .height(40) .margin({ left:16, right:16 }) // è®¾ç½®é—´è· Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Start}) { Text('å¼ ä¸‰').fontSize(16).fontColor("#182431") Text('+123 4567 8901').fontSize(14).fontColor("#66182431") } Blank() Image($r("app.media.phone")) //在应用的resources/base/media目录放置å为phoneçš„èµ„æºæ–‡ä»¶ .width(24) .height(24) Image($r('app.media.dots')) //在应用的resources/base/media目录放置å为dotsçš„èµ„æºæ–‡ä»¶ .width(24) .height(24) .margin({ left:16, right:24 }) // è®¾ç½®é—´è· } .width('100%') .height(56) .backgroundColor('#87CEFA') // é¡¶éƒ¨æ ‡é¢˜æ èƒŒæ™¯è‰²ï¼Œä»…ç”¨äºŽå¼€å‘æµ‹è¯• } } ``` ### åº•éƒ¨è¾“å…¥æ æœ‰äº†é¡¶éƒ¨å·¥å…·æ 的开å‘ç»éªŒï¼Œå¯ä»¥å‘现底部输入æ 的结构更为简å•ï¼Œå®ƒåŒæ ·ä»¥Flexç»„ä»¶ä½œä¸ºçˆ¶å®¹å™¨ï¼ŒåŒæ—¶åŒ…嫿–‡æœ¬è¾“入框(请访问[文本输入组件](../../reference/apis-arkui/arkui-ts/ts-basic-components-textarea.md)查看详细介ç»ï¼‰å’Œæ¶ˆæ¯å‘é€å›¾æ ‡ä¸¤ä¸ªå节点。  ä¸ºäº†ä¾¿äºŽæŸ¥çœ‹çš„æ•ˆæžœï¼Œæˆ‘ä»¬åŒæ ·ç»™åº•部输入æ 设置了淡è“色到背景色。注æ„这里有一个特殊的地方,我们给TextArea设置了flexGrow(1)属性。flexGrow属性仅在父组件是Flex组件时生效,表示Flex容器的剩余空间分é…ç»™æ¤å±žæ€§æ‰€åœ¨çš„组件的比例,flexGrow(1)表示父容器的剩余空间全部分é…ç»™æ¤ç»„件,详è§[Flex布局](../../reference/apis-arkui/arkui-ts/ts-universal-attributes-flex-layout.md)。 | 默认设备 | å¹³æ¿ | | ---------------------------------------- | ---------------------------------------- | |  |  | ```ts @Entry @Component struct BottomArea { build() { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { TextArea({ placeholder:'çŸä¿¡' }) .placeholderColor("#99000000") .caretColor("#007DFF") .backgroundColor("#F1F3F5") .borderRadius(20) .height(40) .flexGrow(1) // 将父容器的剩余空间全部分é…ç»™æ¤ç»„ä»¶ Image($r("app.media.send")) //在应用的resources/base/media目录放置å为sendçš„èµ„æºæ–‡ä»¶ .height(36) .width(36) .opacity(0.4) .margin({ left:12 }) } .height(72) .width('100%') .padding({ left:24, right:24, bottom:8, top:8 }) .backgroundColor('#87CEFA') // 底部输入æ èƒŒæ™¯è‰²ï¼Œä»…ç”¨äºŽå¼€å‘æµ‹è¯• } } ``` ### ä¿¡æ¯åˆ—表 观察信æ¯åˆ—表区域,å¯ä»¥å‘çŽ°å®ƒæ˜¯ç”±ä¸€ä¸ªä¸ªæ¶ˆæ¯æ°”泡组æˆçš„,å¦å¤–æ¶ˆæ¯æ°”泡在默认设备和平æ¿ä¸Šçš„布局有差异。本å°èŠ‚å°†å›´ç»•å¦‚ä¸‹ä¸¤ä¸ªä¸»é¢˜ä»‹ç»å¦‚何实现消æ¯åˆ—表。 - å¦‚ä½•å®žçŽ°è‡ªå®šä¹‰æ¶ˆæ¯æ°”泡组件。 - 如何在默认设备和平æ¿ä¸Šè‡ªé€‚应布局。 | 默认设备 | å¹³æ¿ | | ---------------------------------------- | ---------------------------------------- | |  |  | **æ¶ˆæ¯æ°”泡** å…ˆåšä¸€ä¸ªæœ€ç®€å•çš„æ¶ˆæ¯æ°”泡,通过borderRadius属性å¯ä»¥è®¾ç½®è¾¹æ¡†çš„圆角åŠå¾„(详è§[边框设置](../../reference/apis-arkui/arkui-ts/ts-universal-attributes-border.md))。 | 默认设备 | å¹³æ¿ | | ---------------------------------------- | ---------------------------------------- | |  |  | ```ts @Entry @Component struct MessageBubble { private content: string = "Introduction" build() { Column() { Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) { Text(this.content) .fontSize(16) .lineHeight(21) .padding({ left: 12, right: 12, top: 8, bottom: 8 }) .backgroundColor("#C0EBDF") .borderRadius(24) .fontColor("#182431") }.width('100%') } .margin({left: 24, right: 24 }) .backgroundColor('#87CEFA') // 消æ¯èƒŒæ™¯è‰²ï¼Œä»…用于开å‘和测试 } } ``` 注æ„这个简å•çš„æ¶ˆæ¯æ°”泡,左上角(或å³ä¸Šè§’ï¼‰çš„æ ·å¼ï¼Œä¸Žå®žé™…期望ä¸ç¬¦ã€‚我们先修改å‘逿¶ˆæ¯å³ä¸Šè§’çš„æ ·å¼ï¼ŒæŽ¥æ”¶æ¶ˆæ¯å·¦ä¸Šè§’的实现与之类似。 [Stack组件](../../reference/apis-arkui/arkui-ts/ts-container-stack.md)æ˜¯ä¸€ä¸ªå †å 容器,其å组件按照轴方å‘便¬¡å †å ,åŽä¸€ä¸ªå组件覆盖å‰ä¸€ä¸ªå组件。通过其alignContent接å£ï¼Œå¯ä»¥è®¾ç½®åç»„ä»¶åœ¨å®¹å™¨å†…çš„å¯¹é½æ–¹å¼ï¼Œå¦‚alignContent: Alignment.TopStart代表å组件从左上角对é½ã€‚ | 默认设备 | å¹³æ¿ | | ---------------------------------------- | ---------------------------------------- | |  |  | ```ts @Entry @Component struct MessageBubble { private content: string = "Introduction" build() { Column() { Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) { Stack({ alignContent: Alignment.TopEnd }) { // åœ¨å·¦ä¸Šè§’å †å 一个å°è‰²å— Column() .backgroundColor("#C0EBDF") .borderRadius(4) .width(24) .height(24) Text(this.content) .fontSize(16) .lineHeight(21) .padding({ left: 12, right: 12, top: 8, bottom: 8 }) .backgroundColor("#C0EBDF") .borderRadius(24) .fontColor("#182431") } }.width('100%') } .margin({left: 24, right: 24 }) .backgroundColor('#87CEFA') // 消æ¯èƒŒæ™¯è‰²ï¼Œä»…用于开å‘和测试 } } ``` æŽ¥ä¸‹æ¥æˆ‘ä»¬åœ¨æ¶ˆæ¯æ°”æ³¡ä¸‹æ–¹åŠ ä¸Šæ—¶é—´æ˜¾ç¤ºï¼Œå¦‚ä¸‹å›¾æ‰€ç¤ºï¼Œä¸€ä¸ªæ¶ˆæ¯æ°”泡自定义组件就基本完æˆäº†ã€‚ | 默认设备 | å¹³æ¿ | | ---------------------------------------- | ---------------------------------------- | |  |  | ```ts @Entry @Component struct MessageBubble { private content: string = "Introduction" private time: string = "ä¸Šåˆ 10:35" build() { Column() { Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) { Stack({ alignContent: Alignment.TopEnd }) { Column() .backgroundColor("#C0EBDF") .borderRadius(4) .width(24) .height(24) Text(this.content) .fontSize(16) .lineHeight(21) .padding({ left: 12, right: 12, top: 8, bottom: 8 }) .backgroundColor("#C0EBDF") .borderRadius(24) .fontColor("#182431") } }.width('100%') // åœ¨æ¶ˆæ¯æ°”æ³¡åº•éƒ¨å¢žåŠ æ—¶é—´æ˜¾ç¤º Flex({ alignItems: ItemAlign.Center, direction: FlexDirection.Row, justifyContent: FlexAlign.End}) { Text(this.time) .textAlign(TextAlign.Start) .fontSize(10) .lineHeight(13) .fontColor("#99182431") }.width('100%').margin({ left: 12, right: 24 }) } .margin({left: 24, right: 24 }) .backgroundColor('#87CEFA') // 消æ¯èƒŒæ™¯è‰²ï¼Œä»…用于开å‘和测试 } } ``` å‘é€å‡ºçš„æ¶ˆæ¯å’ŒæŽ¥æ”¶åˆ°çš„æ¶ˆæ¯çš„æ¶ˆæ¯æ°”泡结构基本一致,å¯ä»¥é€šè¿‡å¢žåŠ ä¸€ä¸ªæ ‡å¿—ä½ï¼Œè®©ä¸¤ç§æ¶ˆæ¯å…±ç”¨MessageBubble这个自定义组件,代ç å¦‚ä¸‹æ‰€ç¤ºã€‚å°†è¿™ä¸ªæ ‡å¿—ä½è®¾ç½®true,å¯ä»¥æŸ¥çœ‹æŽ¥æ”¶æ¶ˆæ¯çš„æ•ˆæžœã€‚ | 默认设备 | å¹³æ¿ | | ---------------------------------------- | ---------------------------------------- | |  |  | ```ts @Entry @Component struct MessageBubble { private isReceived:boolean = true // é€šè¿‡æ ‡å¿—ä½ï¼Œåˆ¤æ–是å‘é€or接收场景,进而使用ä¸åŒçš„æ ·å¼ private content:string = "Introduction" private time:string = "今天 10:35" build() { Column() { Flex({ justifyContent:this.isReceived? FlexAlign.Start: FlexAlign.End, alignItems: ItemAlign.Center }) { Stack({ alignContent:this.isReceived? Alignment.TopStart: Alignment.TopEnd }) { Column() .backgroundColor(this.isReceived?"#FFFFFF":"#C0EBDF") .borderRadius(4) .width(24) .height(24) Text(this.content) .fontSize(16) .lineHeight(21) .padding({ left:12, right:12, top:8, bottom:8 }) .backgroundColor(this.isReceived?"#FFFFFF":"#C0EBDF") .borderRadius(24) .fontColor("#182431") } }.width('100%') Flex({ alignItems: ItemAlign.Center, direction: FlexDirection.Row, justifyContent:this.isReceived? FlexAlign.Start: FlexAlign.End }) { Text(this.time) .textAlign(TextAlign.Start) .fontSize(10) .lineHeight(13) .fontColor("#99182431") }.width('100%') .margin({ left:this.isReceived?12:0, right:this.isReceived?0:12 }) } .margin({left:24, right:24 }) .backgroundColor('#87CEFA') // 消æ¯èƒŒæ™¯è‰²ï¼Œä»…用于开å‘和测试 } } ``` **æ …æ ¼å¸ƒå±€** å›žé¡¾æ–¹èˆŸå¼€å‘æ¡†æž¶ä¸€å¤šèƒ½åŠ›ï¼Œæ¶ˆæ¯æ°”泡在默认设备和平æ¿ä¸Šå¸ƒå±€ä¸åŒï¼Œå¯ä»¥å€ŸåŠ©æ …æ ¼å¸ƒå±€æ¥è§£å†³ã€‚为了方便测试,我们预定义一个全局数组。 ```ts interface globalMessageItem { time:string, content:string, isReceived:boolean } const globalMessageList:globalMessageItem[] = [ { time:'ä¸Šåˆ 10:20', content:'项目介ç»', isReceived:false }, { time:'ä¸Šåˆ 10:28', content:'"一次开å‘,多端部署"支撑开å‘è€…å¿«é€Ÿé«˜æ•ˆçš„å¼€å‘æ”¯æŒå¤šç§ç»ˆç«¯è®¾å¤‡å½¢æ€çš„应用,实现对ä¸åŒè®¾å¤‡å…¼å®¹çš„åŒæ—¶ï¼Œæä¾›è·¨è®¾å¤‡çš„æµè½¬ã€è¿ç§»å’ŒååŒçš„分布å¼ä½“验', isReceived:false }, { time:'ä¸Šåˆ 10:32', content:'系统能力', isReceived:true }, { time:'ä¸Šåˆ 10:35', content:'系统能力(å³SystemCapability,缩写为SysCap)指æ“ä½œç³»ç»Ÿä¸æ¯ä¸€ä¸ªç›¸å¯¹ç‹¬ç«‹çš„特性,如è“牙,WIFI,NFC,摄åƒå¤´ç‰ï¼Œéƒ½æ˜¯ç³»ç»Ÿèƒ½åŠ›ä¹‹ä¸€ã€‚æ¯ä¸ªç³»ç»Ÿèƒ½åŠ›å¯¹åº”å¤šä¸ªAPI,éšç€ç›®æ ‡è®¾å¤‡æ˜¯å¦æ”¯æŒè¯¥ç³»ç»Ÿèƒ½åЛ共åŒå˜åœ¨æˆ–消失。', isReceived:true } ] ``` 结åˆ[æ …æ ¼ç»„ä»¶](../../reference/apis-arkui/arkui-ts/ts-container-gridcontainer.md)的定义,考虑我们当å‰çš„实际场景,GridRowçš„å„傿•°è®¾ç½®å¦‚下。 - columnsï¼šæ …æ ¼ç»„ä»¶ä¸çš„列数,当å‰åœºæ™¯é»˜è®¤12列å³å¯ã€‚ - gutterï¼šæ …æ ¼å¸ƒå±€åˆ—é—´è·ï¼Œå½“å‰åœºæ™¯æœªä½¿ç”¨è¯¥å‚数,默认设置为0å³å¯ã€‚ - margin: æ …æ ¼å¸ƒå±€ä¸¤ä¾§é—´è·ï¼Œåœ¨å¼€å‘æ¶ˆæ¯æ°”泡组件时,已ç»è®¾ç½®äº†å·¦å³é—´è·ï¼Œæ•…该属性也默认é…置为0。 æ …æ ¼ä¸ä»…åŒ…å«æˆ‘ä»¬è‡ªå®šä¹‰çš„æ¶ˆæ¯æ°”æ³¡ç»„ä»¶ï¼Œè¯¥ç»„ä»¶åœ¨å„æ–ç‚¹ä¸Šçš„å‚æ•°é…置如下。 | æ–点 | 窗å£å®½åº¦(vp) | æ …æ ¼æ€»åˆ—æ•° | æ¶ˆæ¯æ°”泡å 用的列数 | 接收场景å移的列数 | å‘é€åœºæ™¯å移的列数 | | ---- | --------------- | ----- | --------- | --------- | --------- | | sm | [320, 600) | 12 | 12 | 0 | 0 | | md | [600, 840) | 12 | 8 | 0 | 4 | | lg | [840, +∞) | 12 | 8 | 0 | 4 | | 默认设备 | å¹³æ¿ | | ---------------------------------------- | ---------------------------------------- | |  |  | ```ts import { globalMessageList } from "../data/globalMessageList"; //å°†globalMessageList文件exportåŽå¯¼å…¥ï¼› import { MessageBubble } from "./MessageBubble"; //将文件MessageBubble去除@entry作为组件exportåŽå¯¼å…¥ï¼› @Component export default struct MessageItem { private isReceived?: boolean private content?: string private time?: string build() { GridRow() { GridCol({span: {sm: 12, md: 8, lg: 8}, offset: {sm: 0, md: this.isReceived? 0 : 4, lg: this.isReceived? 0 : 4}}) { Flex({ justifyContent: FlexAlign.End, alignItems: ItemAlign.End }) { MessageBubble({ isReceived: this.isReceived, content: this.content, time: this.time }) } } } } } @Entry @Component struct Conversation { build() { Column() { // éªŒè¯æ•ˆæžœ MessageItem({ isReceived: globalMessageList[1].isReceived, content: globalMessageList[1].content, time: globalMessageList[1].time }) MessageItem({ isReceived: globalMessageList[3].isReceived, content: globalMessageList[3].content, time: globalMessageList[3].time }) }.backgroundColor('#87CEFA') // 消æ¯èƒŒæ™¯è‰²ï¼Œä»…用于开å‘和测试 } } ``` ### ç»„åˆæˆåž‹ 现在会è¯è¯¦æƒ…页é¢çš„é¡¶éƒ¨æ ‡é¢˜æ ã€ä¿¡æ¯åˆ—表åŠåº•部输入æ 都已ç»å‡†å¤‡å®Œæ¯•,将这三部分组åˆèµ·æ¥å³å¯å¾—到完整的页é¢ã€‚ - 通过[Flex组件](../../reference/apis-arkui/arkui-ts/ts-container-flex.md)将三个部分组åˆèµ·æ¥ï¼Œæ³¨æ„justifyContent: FlexAlign.SpaceBetweené…置项是将Flex组件ä¸çš„å…ƒç´ æŒ‰ç…§ä¸»è½´æ–¹å‘å‡åŒ€åˆ†é…,其ä¸ç¬¬ä¸€ä¸ªå…ƒç´ 与顶部对é½ï¼Œæœ€åŽä¸€ä¸ªå…ƒç´ 与底部对é½ã€‚ - 通过[List组件](../../reference/apis-arkui/arkui-ts/ts-container-list.md)å’Œ[ForEachè¯æ³•](../../quick-start/arkts-rendering-control-foreach.md),显示整个消æ¯åˆ—表。 | 默认设备 | å¹³æ¿ | | ---------------------------------------- | ---------------------------------------- | |  |  | ```ts import { globalMessageList,globalMessageItem} from "../data/globalMessageList"; //å°†globalMessageListã€globalMessageItem文件exportåŽå¯¼å…¥ï¼› import { MessageItem } from "./MessageItem"; //将文件MessageItem去除@entry作为组件exportåŽå¯¼å…¥ï¼› import { BottomArea } from "./BottomArea"; //将文件BottomArea去除@entry作为组件exportåŽå¯¼å…¥ï¼› import {TopArea } from "./TopArea"; //将文件TopArea去除@entry作为组件exportåŽå¯¼å…¥ï¼› @Entry @Component struct Conversation { build() { Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start, justifyContent: FlexAlign.SpaceBetween }) { Column() { TopArea() // é¡¶éƒ¨æ ‡é¢˜æ List() { // 消æ¯åˆ—表 ForEach(globalMessageList, (item:globalMessageItem, index) => { ListItem() { MessageItem({ isReceived: item.isReceived, content: item.content, time: item.time }) }}) } .listDirection(Axis.Vertical) .edgeEffect(EdgeEffect.Spring) } BottomArea() // 底部输入æ } .backgroundColor("#F1F3F5") .width('100%') .height('100%') } } ``` çŸä¿¡åº”用在默认设备和平æ¿ä¸Šçš„功能完全相åŒï¼Œå› æ¤é€‰æ‹©äº†éƒ¨ç½²æ¨¡åž‹Aã€‚å€ŸåŠ©æ–¹èˆŸå¼€å‘æ¡†æž¶ä¸€å¤šèƒ½åŠ›ï¼ŒçŸä¿¡åº”用实现了在默认设备和平æ¿ä¸Šå…±ç”¨åŒä¸€ä»½ä»£ç ï¼ŒåŒæ—¶è‡ªç„¶ä¹Ÿå…±ç”¨å®‰è£…包。 在实际开å‘过程ä¸ï¼Œä¼šè¯è¯¦æƒ…页é¢éœ€è¦ä»Žåº•å±‚åšæ•°æ®äº¤äº’ï¼ŒåŒæ—¶è¿˜è¦æ”¯æŒä¿¡æ¯é€‰æ‹©ã€ä¿¡æ¯åˆ 除ã€ä¿¡æ¯å‘é€çжæ€ã€è¾“入框与输入法è”动ç‰ç‰åŠŸèƒ½ï¼Œä¼šæ¯”æœ¬å°èŠ‚ä¸ä»‹ç»çš„åŸºç¡€ç‰ˆæœ¬å¤æ‚很多。 ## 相关实例 基于çŸä¿¡ï¼Œå¯å‚考以下实例: - [ä¿¡æ¯åº”用](https://gitee.com/openharmony/applications_mms/tree/master)