前言
在鴻蒙應用開發過程中,我們經常會遇到需要獲取UI上下文實例或者在非UI上下文中調用UI相關方法的場景。隨著HarmonyOS NEXT的不斷發展,UIContext
?API為我們提供了更加優雅的解決方案。本文將詳細介紹如何使用UIContext
中對應的接口獲取與實例綁定的對象,以及如何以全屏方式拉起元服務。
一、UIContext概述
1.1 什么是UIContext?
在HarmonyOS NEXT的Stage模型中,WindowStage/Window通過loadContent
接口加載頁面并創建UI實例,將頁面內容渲染到關聯的窗口中。每個UI實例都與特定窗口一一關聯。UIContext提供了與特定UI實例關聯的執行上下文,確保UI操作能夠在正確的上下文中執行。
1.2 為什么需要UIContext?
一些全局的UI接口需要依賴具體的UI執行上下文。在非UI頁面(如UIAbility)或異步回調中調用這類接口時,系統可能無法跟蹤到當前UI的上下文,導致接口執行失敗。UIContext解決了這個問題,它讓我們能夠明確指定UI操作的執行上下文。
二、獲取UIContext實例的方法
2.1 在組件內獲取UIContext
在有@Component
裝飾器的組件中,可以直接使用this.getUIContext()
方法獲取UIContext實例:
typescript
@Component struct MyComponent {private uiContext: UIContext = this.getUIContext();build() {// 組件內容} }
2.2 全局獲取和使用UIContext
在EntryAbility.ts的onWindowStageCreate
方法中獲取UIContext實例并存儲到AppStorage中,方便全局使用:
typescript
// EntryAbility.ts onWindowStageCreate(windowStage: window.WindowStage): void {hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');windowStage.loadContent('pages/Index', (err) => {// 獲取UIContext并存儲到AppStoragelet context = windowStage.getMainWindowSync().getUIContext();AppStorage.setOrCreate('UIContext', context);if (err.code) {hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));return;}hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');}); }// 在其他類或組件中使用 const uiContext: UIContext = AppStorage.get('UIContext') as UIContext;
2.3 通過window獲取UIContext
從API version 10開始,可以使用ohos.window
中的getUIContext()
方法獲取UIContext實例:
typescript
import window from '@ohos.window';// 獲取當前窗口的UIContext let windowInstance: window.Window = // 獲取window實例 let uiContext: UIContext = windowInstance.getUIContext();
三、UIContext的核心接口及使用示例
3.1 獲取與實例綁定的對象
UIContext提供了多種方法獲取與特定UI實例綁定的對象:
獲取Font對象
typescript
let font: Font = uiContext.getFont();
獲取MediaQuery對象
typescript
let mediaQuery: MediaQuery = uiContext.getMediaQuery();
獲取Router對象
typescript
let router: Router = uiContext.getRouter();
獲取PromptAction對象
typescript
let promptAction: PromptAction = uiContext.getPromptAction();
獲取ComponentUtils對象
typescript
let componentUtils: ComponentUtils = uiContext.getComponentUtils();
獲取UIInspector對象
typescript
let uiInspector: UIInspector = uiContext.getUIInspector();
3.2 使用animateTo創建動畫
animateTo
接口可以指定由于閉包代碼導致的狀態變化插入過渡動效:
typescript
// xxx.ets @Entry @Component struct AnimateToExample {@State widthSize: number = 250;@State heightSize: number = 100;@State rotateAngle: number = 0;private flag: boolean = true;build() {Column() {Button('change size').width(this.widthSize).height(this.heightSize).margin(30).onClick(() => {if (this.flag) {uiContext.animateTo({duration: 2000,curve: Curve.EaseOut,iterations: 3,playMode: PlayMode.Normal,onFinish: () => {console.info('play end');}}, () => {this.widthSize = 150;this.heightSize = 60;});} else {uiContext.animateTo({}, () => {this.widthSize = 250;this.heightSize = 100;});}this.flag = !this.flag;});}.width('100%').margin({ top: 5 });} }
3.3 使用showAlertDialog顯示警告彈窗
typescript
uiContext.showAlertDialog({title: 'title',message: 'text',autoCancel: true,alignment: DialogAlignment.Bottom,offset: { dx: 0, dy: -20 },gridCount: 3,confirm: {value: 'button',action: () => {console.info('Button-clicking callback');}},cancel: () => {console.info('Closed callbacks');}} );
3.4 使用showActionSheet顯示列表彈窗
typescript
uiContext.showActionSheet({title: '標題',message: '內容',autoCancel: true,confirm: {value: '確認',action: () => {console.info('確認按鈕點擊回調');}},// 其他配置...} );
四、全屏方式拉起元服務的方法
4.1 鴻蒙中常見的拉起方式對比
在HarmonyOS中,有多種方式可以拉起應用或元服務,下表對比了主要的幾種方式:
拉起方式 | 描述 | 典型用途 | 適用場景 | 參數要求 | 特點與限制 |
---|---|---|---|---|---|
openLink | 使用URL Scheme喚起目標應用 | 三方跳轉、H5打開App | 適用于已注冊URI的目標服務 | 需注冊scheme,例如myapp://page?param=x | 通用性強,依賴目標注冊URI,不能確保一定成功 |
startAbility | 顯式或隱式Want啟動指定UIAbility | 跨應用模塊調用、能力聯動 | 應用內跳轉、已知bundleName的組件跳轉 | 需指定bundleName、abilityName、action | 功能強大,多用于深度集成,適合系統內交互 |
openAtomicService | 拉起免安裝元服務(原子服務) | 快速使用外部工具/服務 | 一鍵喚起如掃碼、識圖、剪輯等元服務 | 設置action、serviceIdentity、appId等 | 支持免安裝,需注冊為原子服務,調用鏈受限 |
FullScreenLaunchComponent | 以全屏方式嵌入式啟動目標元服務 | 沉浸式嵌入服務 | 元服務間聯動,如地圖內嵌房產展示 | 需配置FullScreenLaunchComponent權限 | 僅元服務可用,適配復雜、須授權,鴻蒙6前存在兼容性問題 |
4.2 使用FullScreenLaunchComponent全屏拉起元服務
FullScreenLaunchComponent
允許以全屏方式嵌入式啟動元服務組件,當被拉起方授權使用方可以嵌入式運行元服務時,使用方可以全屏嵌入式運行元服務;未授權時,使用方跳出式拉起元服務。
基本使用
typescript
import { InnerFullScreenLaunchComponent, LaunchController } from '@kit.ArkUI';@Entry @Component struct Index {appId1: string = '5765880207853275505'; // 元服務appIdappId2: string = '5765880207854372375'; // 另一個元服務appId@BuilderColumnChild() {Column() {Text('InnerFullScreenLaunchComponent').fontSize(16).margin({top: 100});Button('啟動日出日落元服務').onClick(() => {this.controller.launchAtomicService(this.appId2, {});}).height(30).width('50%').margin({top: 50});Button('啟動充值元服務').onClick(() => {let appId = '5765880207853275489';this.controller.launchAtomicService(appId, {});}).height(30).width('50%').margin({top: 50});}.backgroundColor(Color.Pink).height('100%').width('100%');}controller: LaunchController = new LaunchController();build() {Column() {InnerFullScreenLaunchComponent({content: this.ColumnChild,controller: this.controller,});}.width('100%').height('100%');} }
實現原理
導入模塊:首先需要導入
InnerFullScreenLaunchComponent
和LaunchController
。創建LaunchController:實例化一個拉起控制器,用于控制元服務的拉起行為。
構建界面內容:使用
@Builder
裝飾器構建要顯示的內容,通常包含觸發拉起操作的按鈕。調用launchAtomicService方法:通過控制器的
launchAtomicService
方法拉起指定的元服務,需要傳入元服務的appId和可選參數。
注意事項
系統接口:
InnerFullScreenLaunchComponent
是系統接口,從API Version 12開始支持。繼承要求:如果要在元服務中實現嵌入式運行,必須繼承自
EmbeddableUIAbility
,否則系統無法保證元服務功能正常。權限配置:需要配置
FullScreenLaunchComponent
權限。兼容性:在HarmonyOS 6之前存在兼容性問題,開發時需要注意。
4.3 使用openAtomicService拉起元服務
除了全屏嵌入式拉起,還可以使用openAtomicService
方法直接拉起元服務:
typescript
openAtomicService(appId: string, parameters?: Record<string, Object>, context?: common.UIAbilityContext) {const contextP = context ?? getContext() as common.UIAbilityContext;const options: AtomicServiceOptions = {displayId: 0,parameters};contextP.openAtomicService(appId, options).then(() => {console.log('openAtomicService success');}).catch((err: BusinessError) => {console.error(`openAtomicService failed: ${err.code}, ${err.message}`);}); }// 示例調用 Button('拉起學習通元服務').onClick(() => {this.openAtomicService('5765880207855627899'); });
五、實戰案例:結合UIContext與全屏拉起元服務
下面是一個綜合案例,演示如何在異步回調中使用UIContext執行UI操作,并在操作完成后拉起元服務:
typescript
@Entry @Component struct IntegratedExample {@State private dialogVisible: boolean = false;private uiContext: UIContext = this.getUIContext();private controller: LaunchController = new LaunchController();private targetAppId: string = '5765880207853275505';// 顯示對話框并設置超時后拉起元服務showDialogAndLaunch() {// 使用UIContext顯示對話框this.uiContext.showAlertDialog({title: '確認拉起',message: '是否要全屏拉起元服務?',autoCancel: true,confirm: {value: '確認',action: () => {// 用戶確認后直接拉起this.launchAtomicService();}},cancel: () => {console.info('用戶取消拉起操作');}});// 設置超時,10秒后自動拉起setTimeout(() => {this.launchAtomicService();}, 10000);}// 拉起元服務launchAtomicService() {try {this.controller.launchAtomicService(this.targetAppId, {});console.info('元服務拉起成功');} catch (error) {console.error(`元服務拉起失敗: ${error.code}, ${error.message}`);// 失敗后使用UIContext顯示錯誤信息this.uiContext.showAlertDialog({title: '拉起失敗',message: '元服務拉起失敗,請重試或檢查配置',confirm: {value: '確定',action: () => {}}});}}@BuilderMainContent() {Column() {Text('UIContext與元服務拉起演示').fontSize(20).margin({ bottom: 30 });Button('點擊顯示對話框并拉起元服務').onClick(() => {this.showDialogAndLaunch();}).width('80%').height(40);}.width('100%').height('100%').justifyContent(FlexAlign.Center);}build() {Column() {InnerFullScreenLaunchComponent({content: this.MainContent,controller: this.controller,});}.width('100%').height('100%');} }
六、開發注意事項與最佳實踐
上下文明確性:確保在UI上下文明確的地方使用UIContext方法,避免在UIAbility或異步回調中直接調用UI方法。
錯誤處理:在使用全屏拉起元服務時,始終添加錯誤處理邏輯,應對權限不足、元服務不存在等情況。
用戶體驗:在使用全屏嵌入式拉起時,提供清晰的用戶界面和操作指引,讓用戶了解當前狀態。
權限申請:確保在應用中申請必要的權限,并在嘗試拉起前檢查權限狀態。
兼容性檢查:在使用較新的API(如InnerFullScreenLaunchComponent)時,檢查系統版本兼容性,必要時提供降級方案。
結語
UIContext是HarmonyOS NEXT中非常重要的API,它解決了UI上下文不明確導致的操作失敗問題,為開發者提供了更靈活的UI控制能力。結合全屏拉起元服務的技術,可以創造出更加豐富和沉浸式的用戶體驗。希望通過本文的介紹,能夠幫助大家更好地理解和應用這些技術,開發出更高質量的鴻蒙應用。