• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用UI上下文接口操作界面(UIContext)
2
3## 概述
4
5OpenHarmony支持Stage模型后,存在一个ArkTS引擎里面运行多个ArkUI实例的场景。此时,一个ArkTS引擎下可能会有多个Ability,每个Ability可能有多个Window,每个Window通过loadContent加载页面,生成一个UIContent(ArkUI实例)。
6
7**图1** 多实例关系图
8![multi-instance](figures/multi-instance.png)
9
10FA模型默认只支持一个ArkUI实例,没有多实例的场景。当框架切换到Stage模型后,在FA模型下开放的ArkUI全局接口,在调用时无法明确运行在哪个实例里,存在语义不明确的问题。并且,这些接口实现依赖了ArkUI实例相关的信息,如果实例不明确,会导致运行时会出现预期外的行为。
11
12为了解决此类问题,ArkUI针对Stage模型推出了替代接口,以便满足开发者在多实例场景下的诉求。可使用window的接口方法[getUIContext](../reference/apis-arkui/js-apis-window.md#getuicontext10)或者使用组件内置方法[getUIContext](../reference/apis-arkui/arkui-ts/ts-custom-component-api.md#getuicontext)直接获取当前组件所在的UIContext,并使用[UIContext](../reference/apis-arkui/js-apis-arkui-UIContext.md#uicontext)中对应的接口获取与实例绑定的对象。
13
14## 接口替代关系
15
16部分多实例替代接口如下表所示,UIContext实例支持的全量接口以[UIContext](../reference/apis-arkui/js-apis-arkui-UIContext.md)中描述为准。
17
18|               全局接口                |               替代接口                |            说明            |
19| :-----------------------------------: | :-----------------------------------: | :------------------------: |
20|            @ohos.animator             |            createAnimator             |      自定义动画控制器      |
21|     @ohos.arkui.componentSnapshot     |         getComponentSnapshot          |          组件截图          |
22|      @ohos.arkui.componentUtils       |           getComponentUtils           |         组件工具类         |
23|      @ohos.arkui.dragController       |           getDragController           |         拖拽控制器         |
24|         @ohos.arkui.inspector         |            getUIInspector             |        组件布局回调        |
25|         @ohos.arkui.observer          |             getUIObserver             |          无感监听          |
26|              @ohos.font               |                getFont                |         自定义字体         |
27|             @ohos.measure             |            getMeasureUtil             |          文本计算          |
28|           @ohos.mediaquery            |             getMediaQuery             |          媒体查询          |
29|          @ohos.promptAction           |            getPromptAction            |            弹窗            |
30|             @ohos.router              |               getRouter               |          页面路由          |
31|              AlertDialog              |            showAlertDialog            |          警告弹窗          |
32|              ActionSheet              |            showActionSheet            |        列表选择弹窗        |
33|         CalendarPickerDialog          |                不支持                 |       日历选择器弹窗       |
34|           DatePickerDialog            |         showDatePickerDialog          |      日期滑动选择弹窗      |
35|           TimePickerDialog            |         showTimePickerDialog          |     时间滑动选择器弹窗     |
36|           TextPickerDialog            |         showTextPickerDialog          |     文本滑动选择器弹窗     |
37|              ContextMenu              |       getContextMenuController        |          菜单控制          |
38| vp2px/px2vp/fp2px/px2fp/lpx2px/px2lpx | vp2px/px2vp/fp2px/px2fp/lpx2px/px2lpx |        像素单位转换        |
39|             focusControl              |            getFocusControl            |          焦点控制          |
40|             cursorControl             |           getCursorControl            |          光标控制          |
41|              getContext               |            getHostContext             | 获取当前的Ability的Context |
42|        LocalStorage.getShared         |         getSharedLocalStorage         |  获取Ability传递的Storage  |
43|               animateTo               |               animateTo               |          显式动画          |
44|         animateToImmediately          |                不支持                 |        显式立即动画        |
45
46## 接口切换方法
47
48下述示例,实现了在具体窗口内弹出Toast。ArkUI可感知到是在当前页面下调用,找到对应的UI实例。但是,如果一些复杂场景的起始调用不在页面中,经过了异步调用,作用的实例就可能出现行为不明确的问题。
49
50<!--deprecated_code_no_check-->
51```ts
52import { promptAction } from '@kit.ArkUI'
53
54@Entry
55@Component
56struct Index {
57  build() {
58    Row() {
59      Button()
60        .onClick(() => {
61          promptAction.showToast({
62            message: 'Message Info',
63            duration: 2000
64          });
65        })
66    }
67  }
68}
69```
70下述示例,callNative是Node-API方法,回调如果是由C侧异步触发,执行时无法感知当前页面信息,无法确定响应的UI实例。
71
72<!--deprecated_code_no_check-->
73```ts
74import { promptAction } from '@kit.ArkUI'
75
76@Entry
77@Component
78struct Index {
79  build() {
80    Row() {
81      Button()
82        .onClick(() => {
83          bridge.callNative("xxxx", ()=> {
84            promptAction.showToast({
85              message: 'Message Info',
86              duration: 2000
87            });
88          })
89        })
90    }
91  }
92}
93```
94
95针对上述问题,可使用组件内置方法[`getUIContext`](../reference/apis-arkui/arkui-ts/ts-custom-component-api.md#getuicontext)直接获取当前组件所在的UIContext,并使用[UIContext](../reference/apis-arkui/js-apis-arkui-UIContext.md#uicontext)中的getPromptAction接口获取与实例绑定的对象,使得Toast绑定到具体的实例。
96```ts
97@Entry
98@Component
99struct Index {
100  build() {
101    Row() {
102      Button()
103        .onClick(() => {
104          let uiContext = this.getUIContext();
105          let prompt = uiContext.getPromptAction();
106          bridge.callNative("xxxx", ()=> {
107            prompt.showToast({
108              message: 'Message Info',
109              duration: 2000
110            });
111          })
112        })
113    }
114  }
115}
116```
117
118对于UIContext中没有提供替代的接口(例如,CalendarPickerDialog和animateToImmediately),或者开发者自定义实现的业务行为与多实例相关,需要和实例绑定时(例如,一个代码段),可以使用[UIContext](../reference/apis-arkui/js-apis-arkui-UIContext.md#uicontext)的runScopedTask方法将接口或一段代码段包裹起来。
119
120| UIContext接口 | 说明                 |
121| ------------- | -------------------- |
122| runScopedTask | 执行绑定实例的闭包。 |
123
124上文的示例也可以使用如下方法实现。
125
126<!--deprecated_code_no_check-->
127```ts
128// 执行绑定实例的闭包
129import { promptAction } from '@kit.ArkUI'
130
131@Entry
132@Component
133struct Index {
134  build() {
135    Row() {
136      Button()
137        .onClick(() => {
138          let uiContext = this.getUIContext();
139          uiContext.runScopedTask(() => {
140            promptAction.showToast({
141              message: 'Message Info',
142              duration: 2000
143            });
144          })
145        })
146    }
147  }
148}
149```
150