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 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