OpenHarmony實(shí)現(xiàn)復(fù)合手勢(shì)識(shí)別
應(yīng)用開(kāi)發(fā)中經(jīng)常需要給同一個(gè)組件劃分不同的觸摸熱區(qū),并且不同熱區(qū)觸發(fā)的操作也不同,比如閱讀應(yīng)用通常包含左右兩個(gè)觸摸熱區(qū),用戶(hù)觸摸左側(cè)觸發(fā)向后翻頁(yè),觸摸右側(cè)觸發(fā)向前翻頁(yè);同樣的,視頻應(yīng)用中,長(zhǎng)按視頻播放器的左側(cè)觸發(fā)快退播放,長(zhǎng)按右側(cè)觸發(fā)快進(jìn)播放等等。
當(dāng)前OpenHarmony提供的熱區(qū)設(shè)置屬性(responseRegion)只能在不同的觸摸熱區(qū)中觸發(fā)相同的事件,那么如何實(shí)現(xiàn)不同熱區(qū)不同事件呢,本例即以上述視頻播放場(chǎng)景為例進(jìn)行說(shuō)明。
效果呈現(xiàn)
效果說(shuō)明:開(kāi)始時(shí)視頻以正常速度播放,播放到5秒時(shí),長(zhǎng)按播放器右側(cè)觸發(fā)快進(jìn)播放,播放到14秒時(shí)長(zhǎng)按播放器左側(cè)觸發(fā)快退播放。
環(huán)境要求
本例基于以下環(huán)境開(kāi)發(fā),開(kāi)發(fā)者也可以基于其他適配的版本進(jìn)行開(kāi)發(fā):
- IDE: DevEco Studio 4.0 Release
- SDK: Ohos_sdk_public 4.0.10.13 (API Version 10 Release)
實(shí)現(xiàn)思路
本例即采用上述思路為Video組件的左右兩側(cè)添加不同的交互動(dòng)作。從而實(shí)現(xiàn)長(zhǎng)按視頻播放器的左側(cè)觸發(fā)后退播放,長(zhǎng)按右側(cè)觸發(fā)快進(jìn)播放。
開(kāi)發(fā)步驟
本例詳細(xì)開(kāi)發(fā)步驟如下,開(kāi)發(fā)步驟中僅展示相關(guān)步驟代碼,全量代碼請(qǐng)參考完整代碼章節(jié)的內(nèi)容。
通過(guò)Video組件創(chuàng)建視頻播放器,并添加觸摸手勢(shì),通過(guò)觸摸控制視頻的播放、暫停。
@Component
export struct VideoPlayer{
//...
private isPlaying:boolean = true
private updateTime: number
private videoController:VideoController = new VideoController()
build(){
// 添加視頻組件
Video({src:this.videoSrc, controller:this.videoController, previewUri:this.videoPreviewer,currentProgressRate:this.playRate})
//...
// 獲取當(dāng)前進(jìn)度條的時(shí)間點(diǎn)
.onUpdate((e)=>{
this.updateTime = e.time
})
.gesture(
// 添加觸摸手勢(shì)
TapGesture({count:1})
.onAction((event:GestureEvent)=>{
if (this.isPlaying){
// 觸摸觸發(fā)播放
this.videoController.start()
this.isPlaying = !this.isPlaying
} else {
// 再次觸摸觸發(fā)暫停
this.videoController.pause()
this.isPlaying =!this.isPlaying
}
})
)
}
}
為Video組件添加長(zhǎng)按手勢(shì),通過(guò)長(zhǎng)按手勢(shì)觸發(fā)播放的快退和快進(jìn)動(dòng)作。由于觸摸手勢(shì)和長(zhǎng)按手勢(shì)需要互斥,即一次只能觸發(fā)一種手勢(shì),所以通過(guò)GestureGroup來(lái)實(shí)現(xiàn)手勢(shì)的互斥。
.gesture(
// 通過(guò)GestureGroup的GestureMode.Exclusive參數(shù)控制手勢(shì)互斥
GestureGroup(GestureMode.Exclusive,
// 添加觸摸手勢(shì)
TapGesture({count:1})
.onAction((event:GestureEvent)=>{
if (this.isPlaying){
// 觸摸觸發(fā)播放
this.videoController.start()
this.isPlaying = !this.isPlaying
} else {
// 再次觸摸觸發(fā)暫停
this.videoController.pause()
this.isPlaying =!this.isPlaying
}
}),
// 添加長(zhǎng)按手勢(shì)
LongPressGesture({repeat:true})
// 長(zhǎng)按時(shí)觸發(fā)快進(jìn)或快退
.onAction((event)=>{
//添加快進(jìn)和快退的邏輯,通過(guò)event獲取手勢(shì)坐標(biāo)進(jìn)行判斷。
})
// 長(zhǎng)按結(jié)束后播放速度回歸正常
.onActionEnd(()=>{
// 添加回歸正常播放的邏輯
})
)
)
補(bǔ)充長(zhǎng)按手勢(shì)中的業(yè)務(wù)邏輯:通過(guò)event獲取到觸摸點(diǎn)的x坐標(biāo):localX,當(dāng)localX>=200時(shí),說(shuō)明觸摸點(diǎn)在組件的右側(cè),觸發(fā)快進(jìn)播放;當(dāng)localX<200時(shí),說(shuō)明觸摸點(diǎn)在左側(cè),觸發(fā)快退播放。當(dāng)觸摸停止時(shí),回歸正常播放速度。
// 添加長(zhǎng)按手勢(shì)
LongPressGesture({repeat:true})
// 長(zhǎng)按時(shí)觸發(fā)快進(jìn)或快退
.onAction((event)=>{
// 獲取到觸摸點(diǎn)x坐標(biāo)localX,當(dāng)localX>=200時(shí),說(shuō)明觸摸點(diǎn)在組件的右側(cè),觸發(fā)快進(jìn)播放
if (event.fingerList[0].localX>=200){
// 播放速度變?yōu)?倍速
this.playRate = PlaybackSpeed.Speed_Forward_2_00_X
}
// 當(dāng)localX<200時(shí),說(shuō)明觸摸點(diǎn)在左側(cè),觸發(fā)快退播放
if (event.fingerList[0].localX<200){
if (this.intervalCount===0){
// 通過(guò)進(jìn)度時(shí)間減小來(lái)達(dá)到快退的目的,通過(guò)setInterval來(lái)控制后退的速度,否則會(huì)連續(xù)觸發(fā)后退,瞬間后退到播放起點(diǎn)
this.seekBack = setInterval(()=>{
this.updateTime -= 1
this.videoController.setCurrentTime(this.updateTime)
},500)
}
this.intervalCount = 1
}
})
// 長(zhǎng)按結(jié)束后播放速度回歸正常
.onActionEnd(()=>{
// 播放回歸到1倍速
this.playRate = PlaybackSpeed.Speed_Forward_1_00_X
// 清空計(jì)時(shí)器
clearInterval(this.seekBack)
this.intervalCount = 0
})
完整代碼
本例完整代碼如下:
說(shuō)明:本例中使用的視頻等資源需要替換為開(kāi)發(fā)者自己的資源。
@Entry
@Component
export struct VideoPlayer{
private videoSrc:Resource = $rawfile('video_1.mp4')
private isPlaying:boolean = true
private updateTime: number = 0
private videoPreviewer:Resource = $r('app.media.wandering_previewer')
private videoController:VideoController = new VideoController()
@State playRate:number = 1
private seekBack:number = 0
private intervalCount:number = 0
build(){
Column(){
// 添加視頻組件
Video({src:this.videoSrc, controller:this.videoController, previewUri:this.videoPreviewer,currentProgressRate:this.playRate})
.width('100%')
.height('30%')
.backgroundColor('#fffff0')
.controls(true)
.objectFit(ImageFit.Contain)
// 獲取當(dāng)前進(jìn)度條的時(shí)間點(diǎn)
.onUpdate((e)=>{
this.updateTime = e.time
})
.gesture(
// 通過(guò)GestureGroup的GestureMode.Exclusive參數(shù)控制手勢(shì)互斥
GestureGroup(GestureMode.Exclusive,
// 添加觸摸手勢(shì)
TapGesture({count:1})
.onAction((event:GestureEvent)=>{
if (this.isPlaying){
// 觸摸觸發(fā)播放
this.videoController.start()
this.isPlaying = !this.isPlaying
} else {
// 再次觸摸觸發(fā)暫停
this.videoController.pause()
this.isPlaying =!this.isPlaying
}
}),
// 添加長(zhǎng)按手勢(shì)
LongPressGesture({repeat:true})
// 長(zhǎng)按時(shí)觸發(fā)快進(jìn)或快退
.onAction((event)=>{
// 獲取到觸摸點(diǎn)x坐標(biāo)localX,當(dāng)localX>=200時(shí),說(shuō)明觸摸點(diǎn)在組件的右側(cè),觸發(fā)快進(jìn)播放
if (event.fingerList[0].localX>=200){
// 播放速度變?yōu)?倍速
this.playRate = PlaybackSpeed.Speed_Forward_2_00_X
}
// 當(dāng)localX<200時(shí),說(shuō)明觸摸點(diǎn)在左側(cè),觸發(fā)快退播放
if (event.fingerList[0].localX<200){
if (this.intervalCount===0){
// 通過(guò)進(jìn)度時(shí)間減小來(lái)達(dá)到快退的目的,通過(guò)setInterval來(lái)控制后退的速度,否則會(huì)連續(xù)觸發(fā)后退,瞬間后退到播放起點(diǎn)
this.seekBack = setInterval(()=>{
this.updateTime -= 1
this.videoController.setCurrentTime(this.updateTime)
},500)
}
this.intervalCount = 1
}
})
// 長(zhǎng)按結(jié)束后播放速度回歸正常
.onActionEnd(()=>{
// 播放回歸到1倍速
this.playRate = PlaybackSpeed.Speed_Forward_1_00_X
// 清空計(jì)時(shí)器
clearInterval(this.seekBack)
this.intervalCount = 0
})
)
)
}
.height('100%')
.width('100%')
}
}