鸿蒙交互事件开发07——手势竞争问题
如果你也对鸿蒙开发感兴趣,加入“Harmony自习室”吧!扫描下方名片,关注公众号,公众号更新更快,同时也有更多学习资料和技术讨论群。
1、背景
在文章鸿蒙交互事件开发05——常用的6种手势类型中,有朋友留言,问“可不可以就文中提到的手势竞争,举例子讲一讲?”。
⭐️ 文中提到的手势竞争是什么呢?
是在讨论PanGesture拖动手势时,章节末尾有个tips,内容如下:
大部分可滑动组件,如List、Grid、Scroll、Tab等组件是通过PanGesture实现滑动,在组件内部的子组件绑定拖动手势(PanGesture)或者滑动手势(SwipeGesture)会导致手势竞争。 当在子组件绑定PanGesture时,在子组件区域进行滑动仅触发子组件的PanGesture。如果需要父组件响应,需要通过修改手势绑定方法或者子组件向父组件传递消息进行实现,或者通过修改父子组件的PanGesture参数distance使得拖动更灵敏。当子组件绑定SwipeGesture时,由于PanGesture和SwipeGesture触发条件不同,需要修改PanGesture和SwipeGesture的参数以达到所需效果。 |
这里主要想说明的是:鸿蒙原生组件中的内置滑动组件(List、Scroll等)的滑动是基于拖动手势或者滑动手势来实现,如果我们在这些系统组件中也用了类似的手势作为子组件,那么可能会导致父组件的功能异常。
实际业务场景非常复杂,我这边举一个简单的例子来抛砖引玉。
2、场景举例
有一个List列表,其中List列表的列表项是一个容器,其中这些容器中的内容是可以被拖动的。示意图如下:
这里面我们可以看到有问题出现了。
-
List列表可以上下滑动;
-
list列表项中的子元素也可以被拖动(包括上下拖动);
不出意外,我们在实现子元素拖动时,会使用到PanGesture拖动手势,此时,PanGesture手势将会和List容器的上下滑动冲突。
怎么解决这个问题呢?
跟随前文的tips思路,我们可以考虑在"灵敏度"上面做区分。
例如:
👉🏻 当我们在子项中点击某个按钮时,将子元素的distance设置大一些将事件让给父容器(List)
👉🏻 当我们再点击某个按钮时,将子元素的distance设置小一些,让子元素的事件触发更容易,从而起到子元素响应该手势。
按照上面的方式,我们就可以动态控制手势事件的消费目标了。
3、Demo
实现一个效果:
List列表中显示一系列列表项,每个列表项中包含一个按钮,通过这个按钮可以切换列表项的PanGesture的distance,从而让子容器的PanGesture灵敏度发生变化,达到切换滑动效果的目的。
演示如下:
代码如下:
import util from '@ohos.util';
@Entry
@Component
struct Demo {
gestureDistance: number = 20;
@State data: Array<string> = this.getData(20);
private getData(distance: number): Array<string> {
const arr = [];
for (let index = 0; index < 50; index++) {
arr.push(`内部可以处理拖动的容器 ${index}\n\n\ndistance ${distance}`);
}
return arr;
}
build() {
List() {
ForEach(this.data, (item: string, idx: number) => {
ListItem() {
Row() {
Row() {
Text(item)
Blank()
Button('切换distance')
.onClick(() => {
this.gestureDistance = this.gestureDistance === 20 ? 4 : 20;
console.log('切换 distance ', this.gestureDistance);
this.data = this.getData(this.gestureDistance);
})
}
.padding(5)
.width('100%')
.height(150)
.stateStyles({
pressed: {
.backgroundColor(Color.Brown)
.borderRadius(30)
.animation({duration: 500, curve: Curve.Ease})
},
normal: {
.backgroundColor(Color.Pink)
.borderRadius(10)
.animation({duration: 500, curve: Curve.Ease})
}
})
}
.width('100%')
.padding(5)
.gesture(
PanGesture({
direction: PanDirection.Vertical,
distance: this.gestureDistance,
}).onActionStart((event: GestureEvent) => {
console.log('action start')
})
)
}
})
}
.width('100%')
}
}
🥚彩蛋🥚:请注意demo中按压和释放的动画效果。