diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets index cb6a15e91b0403d9ea116c7e509d914b5a79b816..a3a96a31557bac55ce40aee00f3ba5c571a93c61 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets @@ -18,7 +18,9 @@ import { FlutterView } from '../../view/FlutterView'; import FlutterManager from './FlutterManager'; import { DVModel, DVModelChildren, DynamicView } from '../../view/DynamicView/dynamicView'; import flutter from 'libflutter.so'; + const TAG = "FlutterPage"; + export const OHOS_FLUTTER_PAGE_UPDATE = "ohos_flutter_page_update"; /** @@ -28,11 +30,19 @@ export const OHOS_FLUTTER_PAGE_UPDATE = "ohos_flutter_page_update"; export struct FlutterPage { @Prop viewId: string = "" @Prop xComponentType: XComponentType = XComponentType.SURFACE - + onFocusListener?: () => void | undefined; + onBlurListener?: () => void | undefined; + isFocusFlag: boolean = false; defaultFocusOnTouch = false; - @Builder doNothingBuilder() {} + + @Builder + doNothingBuilder() { + } + @BuilderParam splashScreenView: () => void = this.doNothingBuilder; - @Builder defaultPage() { + + @Builder + defaultPage() { Stack() { ForEach(this.rootDvModel!!, (child: ESObject) => { DynamicView({ @@ -64,7 +74,7 @@ export struct FlutterPage { (ratioInc: boolean, ratio: number) => { if (ratioInc) { Log.i(TAG, "setOnVisibleAreaApproximateChange -> xcomponentId: " + this.viewId + - " ratioInc: " + ratioInc + " ratio: " + ratio); + " ratioInc: " + ratioInc + " ratio: " + ratio); flutter.nativeGetXComponentId(this.viewId); // 保证获取xcomponentid之后再使用无障碍 this.flutterView?.onAccessibilityIsOpen(); @@ -124,8 +134,20 @@ export struct FlutterPage { }); Log.d(TAG, "onDrop"); }) + .onFocus(() => { + Log.d(TAG, "onFocus"); + this.onFocusListener?.(); + this.isFocusFlag = true; + }) + .onBlur(() => { + Log.d(TAG, "onBlur"); + this.onBlurListener?.(); + this.isFocusFlag = false; + }) } - @Builder mouseWheelPage() { + + @Builder + mouseWheelPage() { Stack() { ForEach(this.rootDvModel!!, (child: ESObject) => { DynamicView({ @@ -157,7 +179,7 @@ export struct FlutterPage { (ratioInc: boolean, ratio: number) => { if (ratioInc) { Log.i(TAG, "setOnVisibleAreaApproximateChange -> xcomponentId: " + this.viewId + - " ratioInc: " + ratioInc + " ratio: " + ratio); + " ratioInc: " + ratioInc + " ratio: " + ratio); flutter.nativeGetXComponentId(this.viewId); // 保证获取xcomponentid之后再使用无障碍 this.flutterView?.onAccessibilityIsOpen(); @@ -229,21 +251,31 @@ export struct FlutterPage { this.flutterView?.onMouseWheel("actionEnd", event); }) ) + .onFocus(() => { + Log.d(TAG, "onFocus"); + this.onFocusListener?.(); + this.isFocusFlag = true; + }) + .onBlur(() => { + Log.d(TAG, "onBlur"); + this.onBlurListener?.(); + this.isFocusFlag = false; + }) + } + + public isFocused(): boolean { + return this.isFocusFlag; } - @State showSplashScreen: boolean = true; + @State showSplashScreen: boolean = true; @State checkFullScreen: boolean = true; @State checkKeyboard: boolean = true; @State checkGesture: boolean = true; @State checkMouseWheel: boolean = true; - @StorageLink('nodeWidth') storageLinkWidth: number = 0; @StorageLink('nodeHeight') storageLinkHeight: number = 0; - @State rootDvModel: DVModelChildren | undefined = undefined - @State isNeedUpdate: boolean = false; - private flutterView?: FlutterView | null private lastArea?: Area; private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.Up | PanDirection.Down }); diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterWindow.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterWindow.ets index 36d8d29d836b5b992dbb1f2687edc04019963240..d5259ba7ebe73a69be44125908907e870c20defb 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterWindow.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterWindow.ets @@ -34,8 +34,7 @@ const TAG = "FlutterWindow"; * 支持嵌入其他应用组件的flutter页面 */ export default class FlutterWindow implements Host { - private static ARG_SHOULD_ATTACH_ENGINE_TO_ABILITY: string = "should_attach_engine_to_ability"; - + private static ARG_SHOULD_ATTACH_ENGINE_TO_ABILITY: string = "should_attach_engine_to_ability"; protected uiAbility: UIAbility | null = null protected delegate: FlutterAbilityAndEntryDelegate | null = null protected flutterView: FlutterView | null = null @@ -44,6 +43,7 @@ export default class FlutterWindow implements Host { private parameters: Record = {}; protected engineConfigurator: FlutterEngineConfigurator | null = null protected hasInit: boolean = false; + private isFocusedFlag: boolean = false; constructor(context: Context, params: Record = {}) { this.context = context; @@ -70,9 +70,25 @@ export default class FlutterWindow implements Host { } } - protected windowStageEventCallback = (data: window.WindowStageEventType) => { - let stageEventType: window.WindowStageEventType = data; - switch (stageEventType) { + /** + * 是否由windowStage生命周期处理window事件,如果传false,用户根据场景传递窗口事件到FlutterEngine + * @returns 默认由主窗口window生命周期发送事件到FlutterEntine + */ + protected isWindowStageEventCallbackHandle(): boolean { + return true; + } + + /** + * 部分FlutterWindow场景,并不依赖主window的前后台、焦点事件,依赖组件的事件,所以消息由组件转发 + * 如果使用该方法传递window事件,需重写isWindowStageEventCallbackHandle返回false + * @param event window窗口事件 + */ + public postWindowStageEvent(event: window.WindowStageEventType) { + this.handleWindowStageEvent(event); + } + + private handleWindowStageEvent(event: window.WindowStageEventType) { + switch (event) { case window.WindowStageEventType.SHOWN: // 切到前台 Log.i(TAG, 'windowStage foreground.'); break; @@ -80,10 +96,12 @@ export default class FlutterWindow implements Host { Log.i(TAG, 'windowStage active.'); this.delegate?.getFlutterEngine()?.getTextInputChannel()?.textInputMethodHandler?.handleChangeFocus(true); this?.delegate?.onWindowFocusChanged(true); + this.isFocusedFlag = true; break; case window.WindowStageEventType.INACTIVE: // 失焦状态 Log.i(TAG, 'windowStage inactive.'); this?.delegate?.onWindowFocusChanged(false); + this.isFocusedFlag = false; break; case window.WindowStageEventType.HIDDEN: // 切到后台 Log.i(TAG, 'windowStage background.'); @@ -91,6 +109,17 @@ export default class FlutterWindow implements Host { } } + public isFocused(): boolean { + return this.isFocusedFlag; + } + + protected windowStageEventCallback = (data: window.WindowStageEventType) => { + let stageEventType: window.WindowStageEventType = data; + if (this.isWindowStageEventCallbackHandle()) { + this.handleWindowStageEvent(stageEventType); + } + } + setFlutterEngineConfigurator(configurator: FlutterEngineConfigurator) { this.engineConfigurator = configurator; } @@ -177,9 +206,10 @@ export default class FlutterWindow implements Host { } return param as string } - + shouldDestroyEngineWithHost(): boolean { - if ((this.getCachedEngineId() != null && this.getCachedEngineId().length > 0) || this.delegate!!.isFlutterEngineFromHost()) { + if ((this.getCachedEngineId() != null && this.getCachedEngineId().length > 0) || + this.delegate!!.isFlutterEngineFromHost()) { // Only destroy a cached engine if explicitly requested by app developer. return false; }