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