• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
2324
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&lt;TerminationInfo&gt;)
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