HarmonyOS 鸿蒙Next 手势拖拽时和Swiper组件滑动发生冲突如何解决
HarmonyOS 鸿蒙Next 手势拖拽时和Swiper组件滑动发生冲突如何解决
【问题现象】
用Swiper实现图片的预览、缩放和切换。
期待效果:既可以对图片进行预览、缩放、拖拽,又可以切换不同图片进行预览。
实际效果:只能对图片进行预览、缩放、拖拽,无法切换不同的图片进行预览。
问题代码如下:
// 单手指动作,移动图片PanGesture({ fingers: 1 })
.onActionUpdate((event: GestureEvent) => {
if (this.imageScaleInfo.scaleValue === this.imageScaleInfo.defaultScaleValue) {
// 默认大小下不允许移动
return true;
}
// 修改坐标轴位置
this.imageOffsetInfo.currentX = this.imageOffsetInfo.lastX + event.offsetX;
this.imageOffsetInfo.currentY = this.imageOffsetInfo.lastY + event.offsetY;
return false;
})
.onActionEnd((event: GestureEvent) => {
// 设置图片大小值
this.imageOffsetInfo.stash();
})
【背景知识】
Swiper官方文档链接:滑块视图容器,提供子组件滑动轮播显示的能力。
TapGesture官方文档链接:支持单击、双击和多次点击事件的识别。
【定位思路】
单手指事件会对图片进行位置的移动,跟Swiper组件滑动发生冲突。因此,只需要把单手指的事件取消掉,就可以实现Swiper组件滑动来切换图片。
【解决方案】
根据以上分析,解决方案如下:
(1)取消掉Swiper组件下的缩放效果,即把关于手势事件的问题代码都删除掉,只保留原始的切换图片效果。在点击图片时,进入一个新的图片预览页面,在预览页面添加手势事件的代码,进行图片的缩放和拖拽操作。
(2)当预览结束后,返回到可以滑动切换图片的页面。
图片缩放及预览解决方案如下:
1. 双击切换图片大小
代码示例如下:
TapGesture({ count: 2 })
.onAction(() => {
let fn: Function;
// 已经是放大状态下,双击缩小
if (this.imageScaleInfo.scaleValue > this.imageScaleInfo.defaultScaleValue) {
fn = () => {
this.isEnableSwipe = true;
// 修改图片大小到初始值
this.imageScaleInfo.reset();
// 修改图片偏移量到初始值
this.imageOffsetInfo.reset();
this.matrix = matrix4.identity().copy();
};
} else {
// 已经是缩小状态,双击放大
fn = () => {
this.isEnableSwipe = false;
// 根据图片初始大小和屏幕的大小计算缩放比例的值
const ratio: number = this.calcFitScaleRatio(this.imageDefaultSize, windowSizeManager.get());
// 通过计算出来的缩放比例来对图片进行放大
this.imageScaleInfo.scaleValue = ratio;
// 修改图片偏移量到初始值
this.imageOffsetInfo.reset();
this.matrix = matrix4.identity().scale({
x: ratio,
y: ratio,
}).copy();
this.imageScaleInfo.stash();
}
}
runWithAnimation(fn);
})
2. 双指捏合缩放图片
代码示例如下:
PinchGesture({ fingers: 2, distance: 1 })
.onActionUpdate((event: GestureEvent) => {
// 根据双指捏合事件捕捉到的缩放值,进行图片尺寸的重新计算
this.imageScaleInfo.scaleValue = this.imageScaleInfo.lastValue * event.scale;
// 缩放时不允许大于最大缩放因子+额外缩放因子,不允许小于默认大小-额外缩放因子,额外缩放因子用于提升用户体验
if (this.imageScaleInfo.scaleValue > this.imageScaleInfo.maxScaleValue *
(1 + this.imageScaleInfo.extraScaleValue)
) {
this.imageScaleInfo.scaleValue = this.imageScaleInfo.maxScaleValue *
(1 + this.imageScaleInfo.extraScaleValue);
}
if (this.imageScaleInfo.scaleValue < this.imageScaleInfo.defaultScaleValue *
(1 - this.imageScaleInfo.extraScaleValue)) {
this.imageScaleInfo.scaleValue = this.imageScaleInfo.defaultScaleValue *
(1 - this.imageScaleInfo.extraScaleValue);
}
// matrix默认缩放中心为组件中心
this.matrix = matrix4.identity().scale({
x: this.imageScaleInfo.scaleValue,
y: this.imageScaleInfo.scaleValue,
}).copy();
console.debug(this.imageScaleInfo.toString());
})
// 缩放事件结束,对特殊情况进行判断后,根据计算出来的新的尺寸值,对图片的重新渲染
.onActionEnd((event: GestureEvent) => {
/**
* 当小于默认大小时,恢复为默认大小
*/
if (this.imageScaleInfo.scaleValue < this.imageScaleInfo.defaultScaleValue) {
runWithAnimation(() => {
// 修改图片大小到初始值
this.imageScaleInfo.reset();
// 修改图片偏移量到初始值
this.imageOffsetInfo.reset();
this.matrix = matrix4.identity().copy();
})
}
// 当大于最大缩放因子时,恢复到最大
if (this.imageScaleInfo.scaleValue > this.imageScaleInfo.maxScaleValue) {
runWithAnimation(() => {
this.imageScaleInfo.scaleValue = this.imageScaleInfo.maxScaleValue;
this.matrix = matrix4.identity()
.scale({
x: this.imageScaleInfo.maxScaleValue,
y: this.imageScaleInfo.maxScaleValue
});
})
}
// 根据新计算出来的图片大小值来重新渲染图片
this.imageScaleInfo.stash();
})
3. 单手指拖拽图片至指定位置预览
代码示例如下:
PanGesture({ fingers: 1 })
.onActionUpdate((event: GestureEvent) => {
console.info("event", JSON.stringify(event))
// 根据事件捕捉到的坐标轴值来修改图片的坐标,实现拖动图片的效果
this.imageOffsetInfo.currentX = this.imageOffsetInfo.lastX + event.offsetX;
this.imageOffsetInfo.currentY = this.imageOffsetInfo.lastY + event.offsetY;
return false;
})
.onActionEnd((event: GestureEvent) => {
// 根据新的坐标轴来渲染图片的位置
this.imageOffsetInfo.stash();
})
在HarmonyOS鸿蒙Next中,手势拖拽与Swiper组件滑动发生冲突的问题,通常涉及到手势事件的分发与消费机制。以下是一些专业解决方案:
- 事件拦截:确保Swiper组件正确拦截并处理滑动事件。子组件的拖拽手势应设置为在特定条件下才响应,比如当Swiper不处于滑动状态时。这可以通过自定义组件或修改事件监听逻辑来实现。
- 手势优先级:在组件树中,调整手势识别器的优先级,确保Swiper的滑动手势优先级高于子组件的拖拽手势。这通常涉及修改手势识别器的配置或重写事件处理逻辑。
- 状态同步:使用全局或局部状态管理来同步Swiper和子组件的状态。当Swiper处于滑动状态时,临时禁用或忽略子组件的拖拽手势。
- 条件判断:在子组件的拖拽事件处理函数中,加入条件判断逻辑。如果检测到Swiper正在滑动,则不处理拖拽事件。
这些解决方案可以有效地解决手势拖拽与Swiper组件滑动之间的冲突,提高用户界面的交互体验。如果在实际应用中遇到复杂情况,可能需要根据具体场景进行定制化处理。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html 。