HarmonyOS 鸿蒙Next视频播放类应用键鼠控制实践
HarmonyOS 鸿蒙Next视频播放类应用键鼠控制实践
一、控制视频播放/暂停最佳实践
场景介绍
在使用PC/2in1设备播放视频时,通常需要响应鼠标/键盘操作控制视频播放/暂停,常见的操作类型有:鼠标/触控板/触控屏单击、空格键/Enter键按下,可以分别监听点击和按键的输入事件实现对应功能,本篇文档以AVPlayer播放视频场景为例提供适配指导。
开发步骤
- 定义变量维护视频播放/暂停状态。
- 使用
emitter.on()
注册播放状态变更回调。 - 在avplayer状态机变化回调中调用状态变更。
- 处理
ClickEvent/KeyEvent
事件,判断当前视频播放状态,执行播放/暂停操作。
// 1. 定义变量维护视频播放/暂停状态
isPlaying: boolean = true;
// 2. 使用emitter注册播放状态变更回调
emitter.on(innerEventTrue, (res) => {
if (res.data) {
console.log(`emitter innerEventTrue.`, res.data.flag);
this.isPlaying = res.data.flag;
}
});
emitter.on(innerEventFalse, (res) => {
if (res.data) {
console.log(`emitter innerEventFalse.`, res.data.flag);
this.isPlaying = res.data.flag;
}
});
// 3. 在avplayer状态机变化回调中调用状态变更
this.avPlayer.on('stateChange', async (state, reason) => {
switch (state) {
case 'playing': // After the play interface is successfully invoked, the state machine is reported.
Logger.info(TAG, 'setAVPlayerCallback AVPlayer state playing called.');
let eventDataTrue: emitter.EventData = {
data: {
'flag': true
}
};
emitter.emit(innerEventTrue, eventDataTrue);
break;
case 'paused': {
Logger.info(TAG, 'setAVPlayerCallback AVPlayer state paused called.');
let eventDataFalse: emitter.EventData = {
data: {
'flag': false
}
};
emitter.emit(innerEventFalse, eventDataFalse);
break;
}
}
});
// 4. 处理ClickEvent/KeyEvent事件,判断当前视频播放状态,执行播放/暂停操作
.onClick((event: ClickEvent) => {
console.info('enter click event source:', event.source, 'sourceTool:', event.sourceTool);
if (event.sourceTool !== SourceTool.Unknown) {
this.toggleStartState();
}
})
.onKeyEvent((event: KeyEvent) => {
console.info('enter key event, keyType: ', event.type);
if (event && event.type === KeyType.Down) {
switch (event.keyCode) { // 此处以空格键为例,应用可以根据自己的业务场景响应不同的按键
case KeyCode.KEYCODE_SPACE:
this.toggleStartState();
break;
default:
break;
}
}
})
toggleStartState() {
if (this.isPlaying) {
this.avPlayManager.videoPause();
console.info('toggleStartState pause the video.')
this.isShowProcessBar = true;
} else {
this.avPlayManager.videoPlay();
console.info('toggleStartState start the video.')
}
}
二、调节视频播放进度最佳实践
场景介绍
在使用PC应用播放视频时,通常需要响应用户操作控制视频播放进度,常见的操作类型有:触控板双指水平滑动、触控屏单指水平滑动、键盘左右方向键按下,可以分别监听滑动手势和按键的输入事件实现对应功能,本篇文档以AVPlayer播放视频场景为例提供适配指导
开发步骤
- 定义变量维护视频播放当前时间/总时间。
- 在avlayer初始化完成的回调事件中获取视频播放当前时间/总时间。
- 监听滑动手势,判断是水平方向滑动,则调整视频当前播放事件,在滑动结束时通过
seek
函数调整视频播放进度。 - 监听
keyEvent
事件,根据输入增减播放当前时间,并通过seek
函数调整视频播放进度。
// 1. 定义变量维护视频播放当前时间/总时间
@State durationTime: number = 0;
@State currentTime: number = 0;
// 2. 在avplayer初始化完成的回调事件中获取视频播放当前时间/总时间
this.avPlayManager.initPlayer(this.surfaceId, (avPlayer: media.AVPlayer) => {
this.durationTime = this.avPlayManager.getDurationTime();
setInterval(() => { // Update the current time.
if (!this.isShowProcessMask) {
this.currentTime = this.avPlayManager.getCurrentTime();
}
}, SET_INTERVAL);
this.setTimer();
});
// 3. 监听滑动手势,判断是水平方向滑动,则调整视频当前播放事件,在滑动结束时通过seek函数调整视频播放进度
.gesture(
PanGesture()
.onActionStart((event: GestureEvent) => {
if (event) {
if (Math.abs(event.offsetX) > Math.abs(event.offsetY)) {
this.positionX = this.currentTime
this.isShowProcessMask = true;
}
}
})
.onActionUpdate((event: GestureEvent) => {
if (event) {
if (this.isShowProcessMask) {
this.currentTime = this.positionX + event.offsetX * (this.durationTime / 2000);
console.info('enter PanGesture update, event.offsetX:', event.offsetX, 'currentTime:', this.currentTime);
}
}
})
.onActionEnd((event: GestureEvent) => {
if (this.isShowProcessMask) {
this.avPlayManager.videoSeek(this.currentTime);
this.isShowProcessMask = false;
}
})
)
// 4. 监听keyEvent事件,根据输入增减播放当前时间,并通过seek函数调整视频播放进度
.onKeyEvent((event: KeyEvent) => {
console.info('enter key event, keyType: ', event.type);
if (event && event.type === KeyType.Down) {
switch (event.keyCode) {
case KeyCode.KEYCODE_DPAD_LEFT:
if (this.currentTime - 1000 < 0) {
this.currentTime = 0;
} else {
this.currentTime -= 1000;
}
this.avPlayManager.videoSeek(this.currentTime);
break;
case KeyCode.KEYCODE_DPAD_RIGHT:
if (this.currentTime + 1000 > this.durationTime ) {
this.currentTime = this.durationTime;
} else {
this.currentTime += 1000;
}
this.avPlayManager.videoSeek(this.currentTime);
break;
default:
break;
}
}
})
三、调节视频音量/亮度最佳实践
场景介绍
在使用PC应用播放视频时,通常需要响应用户操作调节视频音量/亮度,常见的操作类型有:在视频左侧区域通过触控板双指竖直滑动、触控屏单指竖直滑动、鼠标滚轮滚动调节亮度在视频右侧区域通过触控板双指竖直滑动、触控屏单指竖直滑动、鼠标滚轮滚动调节音量
开发步骤
- 定义变量维护视频音量/亮度。
- 在avplayer初始化完成的回调事件中获取视频播放当前时间/总时间。
- 监听滑动手势,判断是水平方向滑动,则调整视频当前播放事件,在滑动结束时通过
seek
函数调整视频播放进度。 - 监听
KeyEvent
事件,判断当前视频播放状态,执行播放/暂停操作。
// 1. 定义变量维护视频音量/亮度
@State volume: number = 50;
@State bright: number = 50;
// 2. 在页面加载完成时初始化屏幕亮度
aboutToAppear(): void {
this.mainWin.setWindowBrightness(this.bright / 100);
}
// 3. 在avplayer状态变化到prepared时初始化播放音量
this.avPlayer.on('stateChange', async (state, reason) => {
...
switch (state) {
...
case 'prepared': // This state machine is reported after the prepare interface is successfully invoked.
...
this.avPlayer.setVolume(this.volume);
...
}
});
// 4. 监听滑动手势,判断是竖直方向滑动,如果滑动区域是左半屏则调整屏幕亮度;如果滑动区域是右半屏则调整视频音量
.gesture(
PanGesture()
.onActionStart((event: GestureEvent) => {
if (event) {
if (Math.abs(event.offsetX) > Math.abs(event.offsetY)) {
this.positionX = this.currentTime
this.isShowProcessMask = true;
} else {
if (vp2px(event.fingerList[0].globalX) >= this.surfaceW / 2) {
// 右半屏纵向滑动,调节音量
this.isShowVolumeMask = true;
this.positionY = this.volume;
} else {
// 左半屏纵向滑动,调节亮度
this.isShowBrightnessMask = true;
this.positionY = this.bright;
}
}
}
})
.onActionUpdate((event: GestureEvent) => {
if (event) {
if (this.isShowProcessMask) {
this.currentTime = this.positionX + event.offsetX * (this.durationTime / 2000);
console.info('enter PanGesture update, event.offsetX:', event.offsetX, 'currentTime:', this.currentTime);
}
// 区分输入设备,鼠标和触控板触控屏正负逻辑相反
console.info('enter PanGesture update source:', event.source, 'sourceTool:', event.sourceTool);
if (this.isShowVolumeMask) {
this.volume = this.valueConvert(event);
this.avPlayManager.setVolume(this.volume);
}
if (this.isShowBrightnessMask) {
this.bright = this.valueConvert(event);
this.mainWin.setWindowBrightness(this.bright / 100);
}
}
})
.onActionEnd((event: GestureEvent) => {
if (this.isShowProcessMask) {
this.avPlayManager.videoSeek(this.currentTime);
this.isShowProcessMask = false;
}
if (this.isShowVolumeMask) {
this.isShowVolumeMask = false;
}
if (this.isShowBrightnessMask) {
this.isShowBrightnessMask = false;
}
})
)
// 5. 监听KeyEvent事件,如果是上下方向键,则控制视频音量放大/减小
.onKeyEvent((event: KeyEvent) => {
if (event && event.type === KeyType.Down) {
switch (event.keyCode) {
...
case KeyCode.KEYCODE_DPAD_UP: {
let value = this.volume + 10;
if (value < 0) {
value = 0;
} else if (value > 100) {
value = 100;
}
this.volume = value;
this.avPlayManager.setVolume(this.volume);
break;
}
case KeyCode.KEYCODE_DPAD_DOWN: {
let value = this.volume - 10;
if (value < 0) {
value = 0;
} else if (value > 100) {
value = 100;
}
this.volume = value;
this.avPlayManager.setVolume(this.volume);
break;
}
default:
break;
}
}
})
四、示例代码
参考链接:
更多关于HarmonyOS 鸿蒙Next视频播放类应用键鼠控制实践的实战教程也可以访问 https://www.itying.com/category-93-b0.html
标题
这是段落内容。
这是另一段落内容。
更多关于HarmonyOS 鸿蒙Next视频播放类应用键鼠控制实践的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
鸿蒙Next视频播放应用支持键鼠控制实现方式如下:
- 使用InputSubscriber监听键鼠事件
- 注册KeyCode.BACK等键值处理返回操作
- 通过MouseEvent处理滚轮控制音量
- 监听KeyEvent处理空格键暂停/播放
- 方向键实现快进/后退功能
关键代码示例:
inputMonitor.on(KeyEvent.KEY_DOWN, (event: KeyEvent) => {
if(event.keyCode === KeyCode.SPACE) {
playerCtrl.togglePlay()
}
})
需在config.json声明ohos.permission.INPUT_MONITORING权限。
在HarmonyOS Next中实现视频播放器的键鼠控制功能,您提供的代码示例已经很好地展示了关键实现点。这里补充几点技术细节:
-
事件优先级处理: 建议在
onKeyEvent
和onClick
事件处理中增加事件消费标记(event.stopPropagation
),避免事件冒泡导致多次触发。 -
手势识别优化: 对于进度调节的
PanGesture
,可以增加最小移动阈值判断,避免微小误触:
.onActionStart((event) => {
if(Math.abs(event.offsetX) < 10) return // 忽略小于10px的移动
})
- 音量/亮度调节:
建议增加动画效果平滑过渡,可以使用
animateTo
实现数值变化的平滑过渡:
animateTo({
duration: 100
}, () => {
this.volume = newValue
})
- 性能优化:
频繁的
seek
操作可能会影响性能,可以添加操作间隔限制:
lastSeekTime: number = 0
seekVideo(time: number) {
const now = Date.now()
if(now - this.lastSeekTime < 200) return // 200ms内不重复seek
this.lastSeekTime = now
// ...执行seek操作
}
这些优化点可以使您的视频播放控制更加流畅和稳定。