1# 如何为组件的不同触摸区域添加不同交互动作 2 3## 场景说明 4应用开发中经常需要给同一个组件划分不同的触摸热区,并且不同热区触发的操作也不同,比如阅读应用通常包含左右两个触摸热区,用户触摸左侧触发向后翻页,触摸右侧触发向前翻页;同样的,视频应用中,长按视频播放器的左侧触发快退播放,长按右侧触发快进播放等等。 5当前OpenHarmony提供的热区设置属性(responseRegion)只能在不同的触摸热区中触发相同的事件,那么如何实现不同热区不同事件呢,本例即以上述视频播放场景为例进行说明。 6 7## 效果呈现 8效果说明:开始时视频以正常速度播放,播放到5秒时,长按播放器右侧触发快进播放,播放到14秒时长按播放器左侧触发快退播放。 9 10 11 12## 环境要求 13本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发: 14 15- IDE: DevEco Studio 4.0 Release 16- SDK: Ohos_sdk_public 4.0.10.13 (API Version 10 Release) 17 18## 实现思路 19几乎组件的所有触摸事件都会返回event,通过返回的event可以获取到触摸点的坐标位置,那么就可以根据坐标位置为不同的组件区域添加不同的交互动作。如图:假设有一个长度为200vp的组件,我们希望点击组件的左侧时触发事件A,点击组件的右侧时触发事件B,那么就可以通过触摸点的坐标来判断,当触摸点的x坐标<=100时,触发事件A,反之触发事件B。 20 21 22 23本例即采用上述思路为Video组件的左右两侧添加不同的交互动作。从而实现长按视频播放器的左侧触发后退播放,长按右侧触发快进播放。 24 25## 开发步骤 26本例详细开发步骤如下,开发步骤中仅展示相关步骤代码,全量代码请参考完整代码章节的内容。 271. 通过Video组件创建视频播放器,并添加触摸手势,通过触摸控制视频的播放、暂停。 28 ```ts 29 @Component 30 export struct VideoPlayer{ 31 //... 32 private isPlaying:boolean = true 33 private updateTime: number 34 private videoController:VideoController = new VideoController() 35 36 build(){ 37 // 添加视频组件 38 Video({src:this.videoSrc, controller:this.videoController, previewUri:this.videoPreviewer,currentProgressRate:this.playRate}) 39 //... 40 // 获取当前进度条的时间点 41 .onUpdate((e)=>{ 42 this.updateTime = e.time 43 }) 44 .gesture( 45 // 添加触摸手势 46 TapGesture({count:1}) 47 .onAction((event:GestureEvent)=>{ 48 if (this.isPlaying){ 49 // 触摸触发播放 50 this.videoController.start() 51 this.isPlaying = !this.isPlaying 52 } else { 53 // 再次触摸触发暂停 54 this.videoController.pause() 55 this.isPlaying =!this.isPlaying 56 } 57 }) 58 ) 59 } 60 } 61 ``` 622. 为Video组件添加长按手势,通过长按手势触发播放的快退和快进动作。由于触摸手势和长按手势需要互斥,即一次只能触发一种手势,所以通过GestureGroup来实现手势的互斥。 63 ```ts 64 .gesture( 65 // 通过GestureGroup的GestureMode.Exclusive参数控制手势互斥 66 GestureGroup(GestureMode.Exclusive, 67 // 添加触摸手势 68 TapGesture({count:1}) 69 .onAction((event:GestureEvent)=>{ 70 if (this.isPlaying){ 71 // 触摸触发播放 72 this.videoController.start() 73 this.isPlaying = !this.isPlaying 74 } else { 75 // 再次触摸触发暂停 76 this.videoController.pause() 77 this.isPlaying =!this.isPlaying 78 } 79 }), 80 // 添加长按手势 81 LongPressGesture({repeat:true}) 82 // 长按时触发快进或快退 83 .onAction((event)=>{ 84 //添加快进和快退的逻辑,通过event获取手势坐标进行判断。 85 }) 86 // 长按结束后播放速度回归正常 87 .onActionEnd(()=>{ 88 // 添加回归正常播放的逻辑 89 }) 90 ) 91 ) 92 ``` 933. 补充长按手势中的业务逻辑:通过event获取到触摸点的x坐标:localX,当localX>=200时,说明触摸点在组件的右侧,触发快进播放;当localX<200时,说明触摸点在左侧,触发快退播放。当触摸停止时,回归正常播放速度。 94 ```ts 95 // 添加长按手势 96 LongPressGesture({repeat:true}) 97 // 长按时触发快进或快退 98 .onAction((event)=>{ 99 // 获取到触摸点x坐标localX,当localX>=200时,说明触摸点在组件的右侧,触发快进播放 100 if (event.fingerList[0].localX>=200){ 101 // 播放速度变为2倍速 102 this.playRate = PlaybackSpeed.Speed_Forward_2_00_X 103 } 104 // 当localX<200时,说明触摸点在左侧,触发快退播放 105 if (event.fingerList[0].localX<200){ 106 if (this.intervalCount===0){ 107 // 通过进度时间减小来达到快退的目的,通过setInterval来控制后退的速度,否则会连续触发后退,瞬间后退到播放起点 108 this.seekBack = setInterval(()=>{ 109 this.updateTime -= 1 110 this.videoController.setCurrentTime(this.updateTime) 111 },500) 112 } 113 this.intervalCount = 1 114 } 115 }) 116 // 长按结束后播放速度回归正常 117 .onActionEnd(()=>{ 118 // 播放回归到1倍速 119 this.playRate = PlaybackSpeed.Speed_Forward_1_00_X 120 // 清空计时器 121 clearInterval(this.seekBack) 122 this.intervalCount = 0 123 }) 124 ``` 125 126 127## 完整代码 128本例完整代码如下: 129>  **说明:** 130> 本例中使用的视频等资源需要替换为开发者自己的资源 131 132```ts 133@Entry 134@Component 135export struct VideoPlayer{ 136 private videoSrc:Resource = $rawfile('video_1.mp4') 137 private isPlaying:boolean = true 138 private updateTime: number = 0 139 private videoPreviewer:Resource = $r('app.media.wandering_previewer') 140 private videoController:VideoController = new VideoController() 141 @State playRate:number = 1 142 private seekBack:number = 0 143 private intervalCount:number = 0 144 145 build(){ 146 Column(){ 147 // 添加视频组件 148 Video({src:this.videoSrc, controller:this.videoController, previewUri:this.videoPreviewer,currentProgressRate:this.playRate}) 149 .width('100%') 150 .height('30%') 151 .backgroundColor('#fffff0') 152 .controls(true) 153 .objectFit(ImageFit.Contain) 154 // 获取当前进度条的时间点 155 .onUpdate((e)=>{ 156 this.updateTime = e.time 157 }) 158 .gesture( 159 // 通过GestureGroup的GestureMode.Exclusive参数控制手势互斥 160 GestureGroup(GestureMode.Exclusive, 161 // 添加触摸手势 162 TapGesture({count:1}) 163 .onAction((event:GestureEvent)=>{ 164 if (this.isPlaying){ 165 // 触摸触发播放 166 this.videoController.start() 167 this.isPlaying = !this.isPlaying 168 } else { 169 // 再次触摸触发暂停 170 this.videoController.pause() 171 this.isPlaying =!this.isPlaying 172 } 173 }), 174 // 添加长按手势 175 LongPressGesture({repeat:true}) 176 // 长按时触发快进或快退 177 .onAction((event)=>{ 178 // 获取到触摸点x坐标localX,当localX>=200时,说明触摸点在组件的右侧,触发快进播放 179 if (event.fingerList[0].localX>=200){ 180 // 播放速度变为2倍速 181 this.playRate = PlaybackSpeed.Speed_Forward_2_00_X 182 } 183 // 当localX<200时,说明触摸点在左侧,触发快退播放 184 if (event.fingerList[0].localX<200){ 185 if (this.intervalCount===0){ 186 // 通过进度时间减小来达到快退的目的,通过setInterval来控制后退的速度,否则会连续触发后退,瞬间后退到播放起点 187 this.seekBack = setInterval(()=>{ 188 this.updateTime -= 1 189 this.videoController.setCurrentTime(this.updateTime) 190 },500) 191 } 192 this.intervalCount = 1 193 } 194 }) 195 // 长按结束后播放速度回归正常 196 .onActionEnd(()=>{ 197 // 播放回归到1倍速 198 this.playRate = PlaybackSpeed.Speed_Forward_1_00_X 199 // 清空计时器 200 clearInterval(this.seekBack) 201 this.intervalCount = 0 202 }) 203 ) 204 ) 205 } 206 .height('100%') 207 .width('100%') 208 } 209} 210``` 211 212## 参考 213- [Video组件指导](../application-dev/reference/apis-arkui/arkui-ts/ts-media-components-video.md) 214- [绑定手势指导](../application-dev/reference/apis-arkui/arkui-ts/ts-gesture-settings.md) 215- [组合手势的使用指导](../application-dev/reference/apis-arkui/arkui-ts/ts-combined-gestures.md)