HarmonyOS 鸿蒙Next中画中画开发求助
HarmonyOS 鸿蒙Next中画中画开发求助 目前正利用画中画开发语音通话的小窗模式。但是画中画无法拦截双击窗口放大能力,画中画中组件的事件也无法响应。
sdk版本是5.0.5(17)
运行在手机、平板和PC上,主要为手机和平板。
需求是希望开启小窗之后能够点击上面的按钮,并且双击小窗不会将窗口放大(希望能够固定宽高)。
目前用画中画实现,代码如下:
private pipController?:PiPWindow.PiPController
private nodeController = new XCNodeController()
initPiP(ctx: Context) {
if (this.pipController !== null && this.pipController != undefined) {
return;
}
console.info(TAG, 'onPageShow');
if (!PiPWindow.isPiPEnabled()) {
console.error(TAG, `picture in picture disabled for current OS`);
return;
}
let config: PiPWindow.PiPConfiguration = {
context: ctx,
componentController: new XComponentController(),
customUIController:this.nodeController,
templateType: PiPWindow.PiPTemplateType.VIDEO_CALL,
contentWidth: 1, // 使用typeNode启动画中画时,contentWidth需设置为大于0的值,否则将设置为16:9默认比例
contentHeight: 2, // 使用typeNode启动画中画时,contentHeight需设置为大于0的值,否则将设置为16:9默认比例
};
// 通过create接口创建画中画控制器实例
PiPWindow.create(config).then((controller: PiPWindow.PiPController) => {
this.pipController = controller;
// 通过画中画控制器实例的setAutoStartEnabled接口设置是否需要在应用返回桌面时自动启动画中画
this.pipController.setAutoStartEnabled(true);
// 通过画中画控制器实例的on('stateChange')接口注册生命周期事件回调
this.pipController.on('stateChange', (state: PiPWindow.PiPState, reason: string) => {
let curState: string = '';
switch (state) {
case PiPWindow.PiPState.ABOUT_TO_START:
curState = 'ABOUT_TO_START';
break;
case PiPWindow.PiPState.STARTED:
curState = 'STARTED';
break;
case PiPWindow.PiPState.ABOUT_TO_STOP:
curState = 'ABOUT_TO_STOP';
break;
case PiPWindow.PiPState.STOPPED:
curState = 'STOPPED';
break;
case PiPWindow.PiPState.ABOUT_TO_RESTORE:
curState = 'ABOUT_TO_RESTORE';
break;
case PiPWindow.PiPState.ERROR:
curState = 'ERROR';
break;
default:
break;
}
console.info(`[${TAG}] onStateChange: ${curState}, reason: ${reason}`);
});
this.pipController.on("pipWindowSizeChange", (size)=>{
console.info(`[${TAG}] pipWindowSizeChange: width:${size.width}, height: ${size.height}, scale: ${size.scale}`);
})
}).catch((err: ESObject) => {
console.error(TAG, `Failed to create pip controller. Cause:${err.code}, message:${err.message}`);
});
}
startPip() {
this.pipController?.startPiP().then(() => {
console.info(TAG, `Succeeded in starting pip.`);
}).catch((err:ESObject) => {
console.error(TAG, `Failed to start pip. Cause:${err.code}, message:${err.message}`);
});
}
updateContentSize(width: number, height: number) {
if (this.pipController) {
this.pipController.updateContentSize(width, height);
}
}
// 步骤4:关闭画中画
stopPip() {
if (this.pipController === null || this.pipController === undefined) {
return;
}
let promise: Promise<void> = this.pipController.stopPiP();
promise.then(() => {
console.info(TAG, `Succeeded in stopping pip.`);
}).catch((err: BusinessError) => {
console.error(TAG, `Failed to stop pip. Cause:${err.code}, message:${err.message}`);
});
}
setAutoStart(autoStart: boolean): void {
this.pipController?.setAutoStartEnabled(autoStart);
}
XNodeController.ets
import { BuilderNode, FrameNode, NodeController, UIContext } from '@kit.ArkUI';
const TAG = 'XCNodeController';
// 创建自定义NodeController
export class XCNodeController extends NodeController {
private textNode: BuilderNode<[VoiceCallPipParams]> | null = null;
makeNode(uiContext: UIContext): FrameNode | null {
this.textNode = new BuilderNode(uiContext)
this.textNode.build(wrapBuilder(textBuilder), {
img:''
} as VoiceCallPipParams)
return this.textNode.getFrameNode()
}
update(img: ResourceStr) {
this.textNode?.update({ img } as VoiceCallPipParams)
}
}
export interface VoiceCallPipParams {
img:ResourceStr
}
@Builder
function textBuilder(param:VoiceCallPipParams){
Column(){
Image(param.img)
.height(95).aspectRatio(1)
.borderRadius(50)
.alt($r('app.media.default_head_img'))
Text("挂断")
}
.backgroundColor('#8F69')
.width('100%')
.height('100%')
.gesture(TapGesture({count:2}).onAction(()=>{}))
}
更多关于HarmonyOS 鸿蒙Next中画中画开发求助的实战教程也可以访问 https://www.itying.com/category-93-b0.html
开发者您好,双击放缩是目前画中画的规格。
系统根据设定比例自动适配画中画的窗口大小。updateContentSize接口只能更新比例,无法固定宽高。画中画尺寸详细信息您可参考官网文档:画中画窗口尺寸。
自定义显示的UI无法响应交互事件。具体可参考官网文档:在画中画内容上方展示自定义UI。
如果您期望双击小窗不会将窗口放大(希望能够固定宽高),您方便的话,麻烦您提供下以下信息:
请问您是在语音通话的小窗模式业务场景中使用该能力,点击自定义UI无法响应,双击窗口会将窗口放大,无法固定宽高,方便说明能力不满足可能带来的影响:什么时间用到?是否高频?有无三方库可以做到?若提供该能力,是否会造成大工作量返工?请您注意提供的内容不要包含您或第三方的非公开信息,如给您带来不便,敬请谅解。
更多关于HarmonyOS 鸿蒙Next中画中画开发求助的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
您好,目前放弃使用画中画实现。采用悬浮窗(应用内)加实况窗(应用外)的方案去实现。
好的开发者,后续有任何问题欢迎您随时提问~
遇到同样的问题,楼主有解决吗
鸿蒙Next画中画开发使用UIAbility和WindowStage实现。通过UIAbility的onWindowStageCreate生命周期创建子窗口,调用Window的setWindowMode接口设置窗口模式为WINDOW_MODE_FLOATING。需在module.json5配置abilities的continuable为true并声明ohos.permission.KEEP_BACKGROUND_RUNNING权限。
在HarmonyOS Next中,画中画(PiP)窗口的交互行为主要由系统管理,目前存在以下限制:
-
双击放大行为:画中画窗口的双击放大是系统默认行为,无法通过应用层API直接禁用或拦截。这是为了保持跨应用画中画体验的一致性。
-
组件事件响应:画中画窗口内的组件事件(如点击、手势)默认可能无法正常响应。这是因为画中画窗口运行在独立的渲染上下文中,与主应用窗口的事件传递机制不同。
针对你的需求,可以尝试以下方案:
方案一:使用自定义手势替代双击
在textBuilder中,避免依赖双击手势。可以改为使用长按或其他自定义手势组合来触发你的业务逻辑,从而绕过系统的双击放大。
.gesture(
GestureGroup(
GestureMode.Exclusive,
LongPressGesture().onAction(() => {
// 你的业务逻辑
})
)
)
方案二:调整窗口尺寸策略
虽然无法禁用双击放大,但可以通过updateContentSize方法在窗口尺寸变化后尝试恢复预设尺寸。在pipWindowSizeChange事件回调中处理:
this.pipController?.on("pipWindowSizeChange", (size) => {
console.info(`窗口尺寸变化: width:${size.width}, height: ${size.height}`);
// 如果检测到非预期的尺寸变化,可以尝试恢复
if (size.width !== yourTargetWidth || size.height !== yourTargetHeight) {
this.updateContentSize(yourTargetWidth, yourTargetHeight);
}
});
方案三:组件事件处理优化 确保画中画内的组件使用明确的事件绑定方式。对于按钮点击,建议:
@Builder
function textBuilder(param: VoiceCallPipParams) {
Column() {
Image(param.img)
// ... 其他属性
.onClick(() => {
// 处理图片点击
})
Text("挂断")
.onClick(() => {
// 处理挂断按钮点击
// 注意:这里可能需要通过Emitter或其他方式将事件传递回主应用
})
}
// ... 其他属性
}
重要注意事项:
- 画中画窗口中的事件处理可能需要通过
Emitter或Call机制与主应用通信 VIDEO_CALL模板可能有特定的交互限制,可以尝试使用GENERIC模板获得更灵活的控制- 确保
contentWidth和contentHeight设置为实际需要的比例值,而不是示例中的1:2
目前画中画的能力还在持续演进中,对于更精细的交互控制需求,建议关注后续SDK版本的更新。

