如何為組件的不同觸摸區域添加不同交互動作(通過Event坐標實現)
場景說明
應用開發中經常需要給同一個組件劃分不同的觸摸熱區,并且不同熱區觸發的操作也不同,比如閱讀應用通常包含左右兩個觸摸熱區,用戶觸摸左側觸發向后翻頁,觸摸右側觸發向前翻頁;同樣的,視頻應用中,長按視頻播放器的左側觸發快退播放,長按右側觸發快進播放等等。
當前OpenHarmony提供的熱區設置屬性(responseRegion)只能在不同的觸摸熱區中觸發相同的事件,那么如何實現不同熱區不同事件呢,本例即以上述視頻播放場景為例進行說明。
效果呈現
效果說明:開始時視頻以正常速度播放,播放到5秒時,長按播放器右側觸發快進播放,播放到14秒時長按播放器左側觸發快退播放。
環境要求
本例基于以下環境開發,開發者也可以基于其他適配的版本進行開發:
- IDE: DevEco Studio 4.0 Release
- SDK: Ohos_sdk_public 4.0.10.13 (API Version 10 Release)
實現思路
幾乎組件的所有觸摸事件都會返回event,通過返回的event可以獲取到觸摸點的坐標位置,那么就可以根據坐標位置為不同的組件區域添加不同的交互動作。如圖:假設有一個長度為200vp的組件,我們希望點擊組件的左側時觸發事件A,點擊組件的右側時觸發事件B,那么就可以通過觸摸點的坐標來判斷,當觸摸點的x坐標<=100時,觸發事件A,反之觸發事件B。
本例即采用上述思路為Video組件的左右兩側添加不同的交互動作。從而實現長按視頻播放器的左側觸發后退播放,長按右側觸發快進播放。
開發步驟
本例詳細開發步驟如下,開發步驟中僅展示相關步驟代碼,全量代碼請參考完整代碼章節的內容。
通過Video組件創建視頻播放器,并添加觸摸手勢,通過觸摸控制視頻的播放、暫停。
@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})
//...
// 獲取當前進度條的時間點
.onUpdate((e)=>{
this.updateTime = e.time
})
.gesture(
// 添加觸摸手勢
TapGesture({count:1})
.onAction((event:GestureEvent)=>{
if (this.isPlaying){
// 觸摸觸發播放
this.videoController.start()
this.isPlaying = !this.isPlaying
} else {
// 再次觸摸觸發暫停
this.videoController.pause()
this.isPlaying =!this.isPlaying
}
})
)
}
}
為Video組件添加長按手勢,通過長按手勢觸發播放的快退和快進動作。由于觸摸手勢和長按手勢需要互斥,即一次只能觸發一種手勢,所以通過GestureGroup來實現手勢的互斥。
.gesture(
// 通過GestureGroup的GestureMode.Exclusive參數控制手勢互斥
GestureGroup(GestureMode.Exclusive,
// 添加觸摸手勢
TapGesture({count:1})
.onAction((event:GestureEvent)=>{
if (this.isPlaying){
// 觸摸觸發播放
this.videoController.start()
this.isPlaying = !this.isPlaying
} else {
// 再次觸摸觸發暫停
this.videoController.pause()
this.isPlaying =!this.isPlaying
}
}),
// 添加長按手勢
LongPressGesture({repeat:true})
// 長按時觸發快進或快退
.onAction((event)=>{
//添加快進和快退的邏輯,通過event獲取手勢坐標進行判斷。
})
// 長按結束后播放速度回歸正常
.onActionEnd(()=>{
// 添加回歸正常播放的邏輯
})
)
)
補充長按手勢中的業務邏輯:通過event獲取到觸摸點的x坐標:localX,當localX>=200時,說明觸摸點在組件的右側,觸發快進播放;當localX<200時,說明觸摸點在左側,觸發快退播放。當觸摸停止時,回歸正常播放速度。
// 添加長按手勢
LongPressGesture({repeat:true})
// 長按時觸發快進或快退
.onAction((event)=>{
// 獲取到觸摸點x坐標localX,當localX>=200時,說明觸摸點在組件的右側,觸發快進播放
if (event.fingerList[0].localX>=200){
// 播放速度變為2倍速
this.playRate = PlaybackSpeed.Speed_Forward_2_00_X
}
// 當localX<200時,說明觸摸點在左側,觸發快退播放
if (event.fingerList[0].localX<200){
if (this.intervalCount===0){
// 通過進度時間減小來達到快退的目的,通過setInterval來控制后退的速度,否則會連續觸發后退,瞬間后退到播放起點
this.seekBack = setInterval(()=>{
this.updateTime -= 1
this.videoController.setCurrentTime(this.updateTime)
},500)
}
this.intervalCount = 1
}
})
// 長按結束后播放速度回歸正常
.onActionEnd(()=>{
// 播放回歸到1倍速
this.playRate = PlaybackSpeed.Speed_Forward_1_00_X
// 清空計時器
clearInterval(this.seekBack)
this.intervalCount = 0
})
完整代碼
本例完整代碼如下:
說明:本例中使用的視頻等資源需要替換為開發者自己的資源。
@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)
// 獲取當前進度條的時間點
.onUpdate((e)=>{
this.updateTime = e.time
})
.gesture(
// 通過GestureGroup的GestureMode.Exclusive參數控制手勢互斥
GestureGroup(GestureMode.Exclusive,
// 添加觸摸手勢
TapGesture({count:1})
.onAction((event:GestureEvent)=>{
if (this.isPlaying){
// 觸摸觸發播放
this.videoController.start()
this.isPlaying = !this.isPlaying
} else {
// 再次觸摸觸發暫停
this.videoController.pause()
this.isPlaying =!this.isPlaying
}
}),
// 添加長按手勢
LongPressGesture({repeat:true})
// 長按時觸發快進或快退
.onAction((event)=>{
// 獲取到觸摸點x坐標localX,當localX>=200時,說明觸摸點在組件的右側,觸發快進播放
if (event.fingerList[0].localX>=200){
// 播放速度變為2倍速
this.playRate = PlaybackSpeed.Speed_Forward_2_00_X
}
// 當localX<200時,說明觸摸點在左側,觸發快退播放
if (event.fingerList[0].localX<200){
if (this.intervalCount===0){
// 通過進度時間減小來達到快退的目的,通過setInterval來控制后退的速度,否則會連續觸發后退,瞬間后退到播放起點
this.seekBack = setInterval(()=>{
this.updateTime -= 1
this.videoController.setCurrentTime(this.updateTime)
},500)
}
this.intervalCount = 1
}
})
// 長按結束后播放速度回歸正常
.onActionEnd(()=>{
// 播放回歸到1倍速
this.playRate = PlaybackSpeed.Speed_Forward_1_00_X
// 清空計時器
clearInterval(this.seekBack)
this.intervalCount = 0
})
)
)
}
.height('100%')
.width('100%')
}
}