1# UIExtensionComponent (系统接口) 2 3UIExtensionComponent用于支持在本页面内嵌入其他应用提供的UI。展示的内容在另外一个进程中运行,本应用并不参与其中的布局和渲染。 4 5通常用于有进程隔离诉求的模块化开发场景。 6 7> **说明:** 8> 9> 该组件从API Version 10开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 10> 11> 本模块为系统接口。 12 13## 使用约束 14 15本组件不支持预览。 16 17被拉起的Ability必须是带UI的Ability扩展,如何实现带UI的Ability扩展请参考[实现带UI的Ability扩展](../../apis-ability-kit/js-apis-app-ability-uiExtensionAbility.md)。 18 19必须显示设置组件宽高为非0有效值。 20 21## 子组件 22 23无 24 25## 接口 26 27UIExtensionComponent(want: Want, options?: UIExtensionOptions) 28 29**参数:** 30 31| 参数名 | 参数类型 | 必填 | 参数描述 | 32| --------------------- | ---------------------------------------------------------- | ---- | ------------------ | 33| want | [Want](../../apis-ability-kit/js-apis-app-ability-want.md) | 是 | 要加载的Ability。 | 34| options<sup>11+</sup> | [UIExtensionOptions](#uiextensionoptions11) | 否 | 需要传递的构造项。 | 35 36## 属性 37 38支持[通用属性](ts-universal-attributes-size.md)。 39 40## 事件 41 42不支持[点击](ts-universal-events-click.md)等通用事件。 43 44将事件经过坐标转换后传递给对端Ability处理。 45 46支持以下事件: 47 48### onRemoteReady 49 50onRemoteReady(callback: [Callback](../../apis-basic-services-kit/js-apis-base.md#callback)\<UIExtensionProxy>) 51 52UIExtensionAbility连接完成时的回调,之后可使用proxy向被拉起的Ability发送数据。 53 54**参数:** 55 56| 参数名 | 类型 | 说明 | 57| ---------------------------- | ------ | ------------------------------------------------------------ | 58| proxy | UIExtensionProxy | 用于向对端Ability发送数据。 | 59 60### onReceive 61 62onReceive(callback: [Callback](../../apis-basic-services-kit/js-apis-base.md#callback)\<{ [key: string]: Object }>) 63 64收到被拉起的Ability发送的数据时触发的回调。 65 66**参数:** 67 68| 参数名 | 类型 | 说明 | 69| ---------------------------- | ------ | ------------------------------------------------------------ | 70| data | { [key: string]: Object } | 收到来自对端Ability的数据。 | 71 72### onResult<sup>(deprecated)</sup> 73 74onResult(callback: [Callback](../../apis-basic-services-kit/js-apis-base.md#callback)\<{code: number; want?: Want}>) 75 76被拉起的Ability扩展调用terminateSelfWithResult时会先触发本回调函数,再触发OnRelease。 77 78本回调内可处理对端Ability的结果数据,可参考[AbilityResult](../../apis-ability-kit/js-apis-inner-ability-abilityResult.md)。 79 80> **说明:** 81> 从 API version 10 开始支持,从 API version 12 开始废弃,建议使用[onTerminated](#onterminated12)替代。 82 83**参数:** 84 85| 参数名 | 类型 | 说明 | 86| ---------------------------- | ------ | ------------------------------------------------------------ | 87| code | number | 收到来自对端Ability的处理結果code。 | 88| want | Want | 收到来自对端Ability的处理結果[Want](../../apis-ability-kit/js-apis-app-ability-want.md)。 | 89 90### onRelease<sup>(deprecated)</sup> 91 92onRelease(callback: [Callback](../../apis-basic-services-kit/js-apis-base.md#callback)\<number>) 93 94用于处理被拉起的Ability销毁时的回调。 95 96被拉起的Ability扩展调用terminateSelfWithResult或者terminateSelf时会触发本回调,此时releaseCode为0,即正常销毁。 97 98被拉起的Ability扩展意外Crash或被kill时,触发本回调,此时releaseCode为1。 99 100> **说明:** 101> 从 API version 10 开始支持,从 API version 12 开始废弃,建议使用[onTerminated](#onterminated12)或者[onError](#onerror)替代。 102 103**参数:** 104 105| 参数名 | 类型 | 说明 | 106| ---------------------------- | ------ | ------------------------------------------------------------ | 107| releaseCode | number | 对端Ability销毁时的code,0为正常销毁,1为异常销毁。 | 108 109### onError 110 111onError(callback:[ErrorCallback](../../apis-basic-services-kit/js-apis-base.md#errorcallback)) 112 113被拉起的Ability扩展在运行过程中发生异常时触发本回调。可通过回调参数中的code、name和message获取错误信息并做处理。 114 115**参数:** 116 117| 参数名 | 类型 | 说明 | 118| ---------------------------- | ------ | ------------------------------------------------------------ | 119| err | [BusinessError](../../apis-basic-services-kit/js-apis-base.md#businesserror) | 报错信息。 | 120 121### onTerminated<sup>12+<sup> 122 123onTerminated(callback: Callback<TerminationInfo>) 124 125被拉起的UIExtensionAbility通过调用`terminateSelfWithResult`或者`terminateSelf`正常退出时,触发本回调函数。 126 127**参数:** 128 129| 参数名 | 类型 | 说明 | 130| ------- | ------ | ---------------------------------------------------------------------------------------- | 131| callback | [Callback](../../apis-basic-services-kit/js-apis-base.md#callback)\<[TerminationInfo](#terminationinfo12)> | 回调函数,入参用于接收UIExtensionAbility的返回结果,类型为[TerminationInfo](#terminationinfo12)。 | 132 133> **说明:** 134> 135> - 若UIExtensionAbility通过调用`terminateSelfWithResult`退出,其携带的信息会传给回调函数的入参; 136> - 若UIExtensionAbility通过调用`terminateSelf`退出,上述回调函数的入参中,"code"取默认值"0","want"为"undefined"。 137 138### TerminationInfo<sup>12+<sup> 139 140用于表示被拉起的UIExtensionAbility通过调用`terminateSelfWithResult`或者`terminateSelf`正常退出时的返回结果。 141 142| 属性名 | 类型 | 说明 | 143| ------- | ------ | --------------------------------------------------- | 144| code | number | 被拉起UIExtensionAbility退出时返回的结果码。 | 145| want | [Want](../../apis-ability-kit/js-apis-app-ability-want.md) | 被拉起UIExtensionAbility退出时返回的数据。 | 146 147## UIExtensionOptions<sup>11+</sup> 148用于在UIExtensionComponent进行构造的时传递可选的构造参数。 149 150**参数:** 151 152| 参数名 | 参数类型 | 必填 | 参数描述 | 153| ---- | ---------------------------------------- | ---- | --------------- | 154| isTransferringCaller | boolean | 否 | 在使用UIExtensionComponent嵌套时,设置当前UIExtensionComponent是否转发上一级的Caller信息。</br> 默认值:false。 | 155| placeholder<sup>12+<sup> | [ComponentContent](../js-apis-arkui-ComponentContent.md) | 否 | 设置占位符,在UIExtensionComponent与UIExtensionAbility建立连接前显示。 | 156| dpiFollowStrategy<sup>12+<sup> | [DpiFollowStrategy](ts-container-ui-extension-component-sys.md#dpifollowstrategy12) | 否 | 提供接口支持设置DPI跟随宿主或跟随UIExtensionAbility。</br> 默认值:FOLLOW_UI_EXTENSION_ABILITY_DPI。 | 157 158## DpiFollowStrategy<sup>12+</sup> 159 160| 名称 | 描述 | 161| -------------------------------- | --------------- | 162| FOLLOW_HOST_DPI | 表示DPI跟随宿主。 | 163| FOLLOW_UI_EXTENSION_ABILITY_DPI | 表示DPI跟随UIExtensionAbility。 | 164 165## UIExtensionProxy 166 167用于在双方建立连接成功后,组件使用方向被拉起的Ability发送数据、订阅和取消订阅注册。 168 169### send 170 171send(data: { [key: string]: Object }): void 172 173用于在双方建立连接成功后,组件使用方向被拉起的Ability发送数据的场景,提供异步发送数据。 174 175**系统能力:** SystemCapability.ArkUI.ArkUI.Full 176 177**参数:** 178 179| 参数名 | 参数类型 | 必填 | 参数描述 | 180| ---- | ---------------------------------------- | ---- | --------------- | 181| data | { [key: string]: Object } | 是 | 异步发送给被拉起的扩展Ability的数据。 | 182 183### sendSync<sup>11+</sup> 184 185sendSync(data: { [key: string]: Object }): { [key: string]: Object } 186 187用于在双方建立连接成功后,组件使用方向被拉起的Ability发送数据的场景,提供同步发送数据。 188 189**系统能力:** SystemCapability.ArkUI.ArkUI.Full 190 191**参数:** 192 193| 参数名 | 参数类型 | 必填 | 参数描述 | 194| ---- | ---------------------------------------- | ---- | --------------- | 195| data | { [key: string]: Object } | 是 | 同步发送给被拉起的扩展Ability的数据。 | 196 197**返回值:** 198 199| 类型 | 描述 | 200| ---- | ----| 201|{ [key: string]: Object } | 扩展Ability回复的数据。 | 202 203**错误码:** 204 205| 错误号 | 描述 | 206| ---- | ----| 207| 100011 | 扩展Ability未注册同步回调 | 208| 100012 | 数据发送失败 | 209 210### on('asyncReceiverRegister')<sup>11+</sup> 211 212on(type: 'asyncReceiverRegister', callback: (proxy: UIExtensionProxy) => void): void 213 214用于在双方建立连接成功后,组件使用方订阅被拉起的Ability发生异步注册的场景。 215 216**系统能力:** SystemCapability.ArkUI.ArkUI.Full 217 218**参数:** 219 220| 参数名 | 参数类型 |必填 | 参数描述 | 221| ------ | -------- |---- | ------- | 222| type | string | 是 | 代表订阅扩展Ability发生异步注册回调。 | 223| callback | (proxy: UIExtensionProxy) => void | 是 | 订阅扩展Ability注册setReceiveDataCallback后触发的回调。 | 224 225### on('syncReceiverRegister')<sup>11+</sup> 226 227on(type: 'syncReceiverRegister', callback: (proxy: UIExtensionProxy) => void): void 228 229用于在双方建立连接成功后,组件使用方订阅被拉起的Ability发生同步注册的场景。 230 231**系统能力:** SystemCapability.ArkUI.ArkUI.Full 232 233**参数:** 234 235| 参数名 | 参数类型 |必填 | 参数描述 | 236| ------ | -------- |---- | ------- | 237| type | string | 是 | 订阅扩展Ability发生同步注册回调。 | 238| callback | (proxy: UIExtensionProxy) => void | 是 | 扩展Ability注册setReceiveDataForResultCallback后触发的回调。 | 239 240### off('asyncReceiverRegister')<sup>11+</sup> 241 242off(type: 'asyncReceiverRegister', callback?: (proxy: UIExtensionProxy) => void): void 243 244用于在双方建立连接成功后,组件使用方取消订阅被拉起的Ability发生异步注册的场景。 245 246**系统能力:** SystemCapability.ArkUI.ArkUI.Full 247 248**参数:** 249 250| 参数名 | 参数类型 | 必填 | 参数描述 | 251| ------ | -------- | ----- | ------- | 252| type | string | 是 | 取消订阅扩展Ability发生异步注册回调。 | 253| callback | (proxy: UIExtensionProxy) => void | 否 | 为空代表取消订阅所有扩展Ability异步注册后触发回调。<br> 非空代表取消订阅异步对应回调。 | 254 255### off('syncReceiverRegister')<sup>11+</sup> 256 257off(type: 'syncReceiverRegister', callback?: (proxy: UIExtensionProxy) => void): void 258 259用于在双方建立连接成功后,组件使用方取消订阅被拉起的Ability发生同步注册的场景。 260 261**系统能力:** SystemCapability.ArkUI.ArkUI.Full 262 263**参数:** 264 265| 参数名 | 参数类型 | 必填 | 参数描述 | 266| ------ | -------- | ----- | ------- | 267| type | string | 是 | 取消订阅扩展Ability发生同步注册回调。 | 268| callback | (proxy: UIExtensionProxy) => void | 否 | 为空代表取消订阅所有扩展Ability同步注册后触发回调<br> 非空代表取消订阅同步对应回调。 | 269 270## 示例 271 272### 示例1 (加载UIextension) 273 274本示例仅展示组件使用的方法和扩展的Ability,实际运行需在设备中安装bundleName为"com.example.uiextensionprovider",abilityName为"UIExtensionProvider"的Ability扩展。 275 276```ts 277// 组件使用示例: 278import { ComponentContent } from '@kit.ArkUI'; 279class Params { 280} 281@Builder 282function LoadingBuilder(params: Params) { 283 Column() { 284 LoadingProgress() 285 .color(Color.Blue) 286 } 287} 288@Entry 289@Component 290struct Second { 291 @State message1: string = 'Hello World 1' 292 @State message2: string = 'Hello World 2' 293 @State message3: string = 'Hello World 3' 294 @State visible: Visibility = Visibility.Hidden 295 @State wid: number = 300 296 @State hei: number = 300 297 private proxy: UIExtensionProxy | null = null; 298 private contentNode = new ComponentContent(this.getUIContext(), wrapBuilder(LoadingBuilder), new Params); 299 300 301 build() { 302 Row() { 303 Column() { 304 Text(this.message1).fontSize(30) 305 Text(this.message2).fontSize(30) 306 Text(this.message3).fontSize(30) 307 UIExtensionComponent({ 308 bundleName : "com.example.newdemo", 309 abilityName: "UIExtensionProvider", 310 parameters: { 311 "ability.want.params.uiExtensionType": "dialog" 312 }}, 313 { 314 placeholder: this.contentNode 315 }) 316 .width(this.wid) 317 .height(this.hei) 318 .border({width: 5, color: Color.Blue}) 319 .onReceive((data) => { 320 console.info('Lee onReceive, for test') 321 this.message3 = JSON.stringify(data['data']) 322 }) 323 .onTerminated((info) => { 324 console.info('onTerminated: code =' + info.code + ', want = ' + JSON.stringify(info.want)); 325 }) 326 .onRemoteReady((proxy) => { 327 console.info('onRemoteReady, for test') 328 this.proxy = proxy 329 330 this.proxy.on("syncReceiverRegister", syncRegisterCallback1); 331 // this.proxy.on("syncReceiverRegister", syncRegisterCallback2); 332 333 334 // this.proxy.off("syncReceiverRegister"); 335 336 // this.proxy.off("syncReceiverRegister", (proxy) => { 337 // console.info("off invoke for test, type is syncReceiverRegister"); 338 // }); 339 340 this.proxy.on("asyncReceiverRegister", (proxy1) => { 341 console.info("on invoke for test, type is asyncReceiverRegister"); 342 }); 343 // 344 // this.proxy.off("asyncReceiverRegister"); 345 }) 346 347 Button("点击向UIExtensionAbility发送数据").onClick(() => { 348 if (this.proxy != undefined) { 349 this.proxy.send({data: "你好1"}) 350 351 try { 352 let re = this.proxy.sendSync({data: "你好2"}) 353 console.info("for test, re=" + JSON.stringify(re)); 354 } catch (err) { 355 console.error(`sendSync failed for test. errCode=${err.code}, msg=${err.message}`); 356 } 357 } 358 }) 359 } 360 .width('100%') 361 } 362 .height('100%') 363 } 364} 365 366function syncRegisterCallback1(proxy: UIExtensionProxy) { 367 console.info("on invoke for test, syncRegisterCallback1, type is syncReceiverRegister"); 368} 369 370function syncRegisterCallback2(proxy: UIExtensionProxy) { 371 console.info("on invoke for test, syncRegisterCallback2, type is syncReceiverRegister"); 372} 373``` 374 375```ts 376// 扩展入口文件UIExtensionProvider.ts 377import { UIExtensionAbility, UIExtensionContentSession, Want } from '@kit.AbilityKit'; 378 379const TAG: string = '[UIExtAbility]' 380export default class UIExtAbility extends UIExtensionAbility { 381 382 onCreate() { 383 console.log(TAG, `UIExtAbility onCreate`) 384 } 385 386 onForeground() { 387 console.log(TAG, `UIExtAbility onForeground`) 388 } 389 390 onBackground() { 391 console.log(TAG, `UIExtAbility onBackground`) 392 } 393 394 onDestroy() { 395 console.log(TAG, `UIExtAbility onDestroy`) 396 } 397 398 onSessionCreate(want: Want, session: UIExtensionContentSession) { 399 console.log(TAG, `UIExtAbility onSessionCreate, want: ${JSON.stringify(want)}`) 400 let param: Record<string, UIExtensionContentSession> = { 401 'session': session 402 }; 403 let storage: LocalStorage = new LocalStorage(param); 404 session.loadContent('pages/extension', storage); 405 } 406 407 onSessionDestroy(session: UIExtensionContentSession) { 408 console.log(TAG, `UIExtAbility onSessionDestroy`) 409 } 410} 411``` 412 413```ts 414// 扩展Ability入口页面文件extension.ets 415import { UIExtensionContentSession } from '@kit.AbilityKit'; 416 417let storage = LocalStorage.getShared() 418AppStorage.setOrCreate('message', 'UIExtensionAbility') 419 420@Entry(storage) 421@Component 422struct Extension { 423 @StorageLink('message') storageLink: string = ''; 424 private session: UIExtensionContentSession | undefined = storage.get<UIExtensionContentSession>('session'); 425 pathStack: NavPathStack = new NavPathStack() 426 427 @Builder 428 PageMap(name: string) { 429 if (name === "hello") { 430 pageOneTmp() 431 } 432 } 433 434 onPageShow() { 435 if (this.session != undefined) { 436 this.session.setReceiveDataCallback((data)=> { 437 this.storageLink = JSON.stringify(data) 438 console.info("invoke for test, handle callback set by setReceiveDataCallback successfully"); 439 }) 440 441 this.session.setReceiveDataForResultCallback(func1) 442 } 443 } 444 445 build() { 446 Navigation(this.pathStack) { 447 Row() { 448 Column() { 449 Text(this.storageLink) 450 .fontSize(20) 451 .fontWeight(FontWeight.Bold) 452 Button("点击向Component发送数据").onClick(()=>{ 453 if (this.session != undefined) { 454 this.session.sendData({"data": 543321}) 455 console.info('send 543321, for test') 456 } 457 }) 458 Button("terminate").onClick(()=> { 459 if (this.session != undefined) { 460 this.session.terminateSelf(); 461 } 462 storage.clear() 463 }) 464 Button("terminate with result").onClick(()=>{ 465 if (this.session != undefined) { 466 this.session.terminateSelfWithResult({ 467 resultCode: 0, 468 want: { 469 bundleName: "myBundleName", 470 parameters: { "result": 123456 } 471 } 472 }) 473 } 474 storage.clear() 475 }) 476 477 Button("点击跳转").onClick(()=> { 478 this.pathStack.pushPath({ name: "hello"}) 479 }) 480 } 481 } 482 .height('100%') 483 }.navDestination(this.PageMap) 484 .mode(NavigationMode.Stack) 485 } 486} 487 488// pageOne 489@Component 490export struct pageOneTmp { 491 pathStack: NavPathStack = new NavPathStack() 492 493 build() { 494 NavDestination() { 495 Column() { 496 Text("Hello World") 497 }.width('100%').height('100%') 498 }.title("pageOne") 499 .onBackPressed(() => { 500 const popDestinationInfo = this.pathStack.pop() // 弹出路由栈栈顶元素 501 console.log('pop' + '返回值' + JSON.stringify(popDestinationInfo)) 502 return true 503 }) 504 .onReady((context: NavDestinationContext) => { 505 this.pathStack = context.pathStack 506 }) 507 } 508} 509 510function func1(data: Record<string, Object>): Record<string, Object> { 511 let linkToMsg: SubscribedAbstractProperty<string> = AppStorage.link('message'); 512 linkToMsg.set(JSON.stringify(data)) 513 console.info("invoke for test, handle callback set by setReceiveDataForResultCallback successfully"); 514 return data; 515} 516 517``` 518 519### 示例2 (UEC内外部同时响应滚动时隔离处理) 520 521本示例展示了当UIExtensionComponent组件使用方和扩展的Ability同时使用[Scroll](ts-container-scroll.md)容器的场景,通过对UIExtensionComponent设置手势拦截处理,实现当UIExtensionComponent内部滚动时,外部组件不响应滚动。 522 523手势使用方式: 524组件内部滚动:手指在组件内部进行滚动操作; 525组件外部滚动:拖动外部滚动条进行滚动。 526 527实际运行时需先在设备中安装bundleName为"com.example.uiextensionprovider",abilityName为"UIExtensionProvider"的Ability扩展。 528 529```ts 530// 组件使用示例 531@Entry 532@Component 533struct Second { 534 @State message1: string = 'Hello World 1' 535 @State message2: string = 'Hello World 2' 536 @State message3: string = 'Hello World 3' 537 @State visible: Visibility = Visibility.Hidden 538 @State wid: number = 300 539 @State hei: number = 300 540 private scroller: Scroller = new Scroller(); 541 private arr: number[] = [0, 1, 2, 3, 4, 5, 6] 542 543 build() { 544 Column() { 545 // 可滚动的容器组件 546 Scroll(this.scroller) { 547 Column() { 548 Text(this.message1).fontSize(30) 549 Text(this.message2).fontSize(30) 550 Text(this.message3).fontSize(30) 551 552 // 重复设置组件,构造滚动内容 553 ForEach(this.arr, (item: number) => { 554 UIExtensionComponent({ 555 bundleName: "com.example.newdemo", 556 abilityName: "UIExtensionProvider", 557 parameters: { 558 "ability.want.params.uiExtensionType": "sys/commonUI" 559 } 560 }) 561 .width(this.wid) 562 .height(this.hei) 563 // 设置手势拦截,UEC外部组件不响应滚动 564 .gesture(PanGesture().onActionStart(() => { 565 console.info('UIExtensionComponent PanGesture onAction') 566 })) 567 .border({ width: 5, color: Color.Blue }) 568 .onReceive((data) => { 569 console.info('Lee onReceive, for test') 570 this.message3 = JSON.stringify(data['data']) 571 }) 572 .onTerminated((info) => { 573 console.info('onTerminated: code =' + info.code + ', want = ' + JSON.stringify(info.want)); 574 }) 575 .onRemoteReady((proxy) => { 576 console.info('onRemoteReady, for test') 577 }) 578 }, (item: string) => item) 579 } 580 .width('100%') 581 } 582 .scrollable(ScrollDirection.Vertical) // 滚动方向纵向 583 .scrollBar(BarState.On) // 滚动条常驻显示 584 .scrollBarColor(Color.Gray) // 滚动条颜色 585 .scrollBarWidth(10) // 滚动条宽度 586 .friction(0.6) 587 .edgeEffect(EdgeEffect.None) 588 .onWillScroll((xOffset: number, yOffset: number, scrollState: ScrollState) => { 589 console.info(xOffset + ' ' + yOffset) 590 }) 591 .onScrollEdge((side: Edge) => { 592 console.info('To the edge') 593 }) 594 .onScrollStop(() => { 595 console.info('Scroll Stop') 596 }) 597 } 598 .height('100%') 599 } 600} 601``` 602 603```ts 604// 扩展入口文件UIExtensionProvider.ts 605import { UIExtensionAbility, UIExtensionContentSession, Want } from '@kit.AbilityKit'; 606 607const TAG: string = '[UIExtAbility]' 608export default class UIExtAbility extends UIExtensionAbility { 609 610 onCreate() { 611 console.log(TAG, `UIExtAbility onCreate`) 612 } 613 614 onForeground() { 615 console.log(TAG, `UIExtAbility onForeground`) 616 } 617 618 onBackground() { 619 console.log(TAG, `UIExtAbility onBackground`) 620 } 621 622 onDestroy() { 623 console.log(TAG, `UIExtAbility onDestroy`) 624 } 625 626 onSessionCreate(want: Want, session: UIExtensionContentSession) { 627 console.log(TAG, `UIExtAbility onSessionCreate, want: ${JSON.stringify(want)}`) 628 let param: Record<string, UIExtensionContentSession> = { 629 'session': session 630 }; 631 let storage: LocalStorage = new LocalStorage(param); 632 session.loadContent('pages/extension', storage); 633 } 634 635 onSessionDestroy(session: UIExtensionContentSession) { 636 console.log(TAG, `UIExtAbility onSessionDestroy`) 637 } 638} 639``` 640 641```ts 642// 扩展Ability入口页面文件extension.ets 643@Entry 644@Component 645struct Extension { 646 @StorageLink('message') storageLink: string = ''; 647 private scroller: Scroller = new Scroller(); 648 private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8] 649 650 build() { 651 Column() { 652 // 可滚动的容器组件 653 Scroll(this.scroller) { 654 Column() { 655 Text('Test demo') 656 .fontSize(20) 657 .fontWeight(FontWeight.Bold) 658 // 重复设置组件,构造滚动内容 659 ForEach(this.arr, (item: number) => { 660 Text(item.toString()) 661 .width('90%') 662 .height(150) 663 .backgroundColor(Color.Pink) 664 .borderRadius(15) 665 .fontSize(16) 666 .textAlign(TextAlign.Center) 667 .margin({ top: 10 }) 668 }, (item: string) => item) 669 } 670 } 671 672 } 673 .height('100%') 674 } 675} 676``` 677