温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦!
Harmonyos NEXT 图片预览组件之手势处理实现(二)
效果预览
一、双指旋转手势实现(续)
在上一篇文章中,我们介绍了图片预览组件的单指拖动和双指缩放手势实现。本文将继续介绍双指旋转手势和双击缩放手势的实现细节。
1. 旋转手势处理逻辑
双指旋转手势的核心逻辑包括:
RotationGesture({ angle: this.imageRotateInfo.startAngle })
.onActionUpdate((event: GestureEvent) => {
let angle = this.imageRotateInfo.lastRotate + event.angle
if (event.angle > 0) {
angle -= this.imageRotateInfo.startAngle;
} else {
angle += this.imageRotateInfo.startAngle;
}
this.matrix = matrix4.identity()
.scale({
x: this.imageScaleInfo.scaleValue,
y: this.imageScaleInfo.scaleValue
})
.rotate({
x: 0,
y: 0,
z: 1,
angle: angle,
}).copy();
this.imageRotateInfo.currentRotate = angle;
})
.onActionEnd((event: GestureEvent) => {
let rotate = simplestRotationQuarter(this.imageRotateInfo.currentRotate);
runWithAnimation(() => {
this.imageRotateInfo.currentRotate = rotate;
this.matrix = matrix4.identity()
.scale({
x: this.imageScaleInfo.scaleValue,
y: this.imageScaleInfo.scaleValue
})
.rotate({
x: 0,
y: 0,
z: 1,
angle: rotate,
}).copy();
this.imageRotateInfo.stash();
})
})
旋转手势的处理逻辑包括:
- 设置触发旋转的最小角度阈值(startAngle),防止误触
- 根据event.angle计算新的旋转角度,基于上次旋转的结果(lastRotate)
- 应用矩阵变换,实现图片的旋转效果
- 手势结束时,将旋转角度对齐到最接近的90度倍数(0°、90°、180°、270°)
- 保存当前旋转角度为最后旋转角度,用于下次旋转的基准计算
2. 角度对齐处理
为了提供更好的用户体验,组件在旋转手势结束时会将图片角度对齐到最接近的90度倍数:
export function simplestRotationQuarter(angle: number): number {
// 将角度转换为0-360范围内
let normalizedAngle = angle % 360;
if (normalizedAngle < 0) {
normalizedAngle += 360;
}
// 计算最接近的90度倍数
let quarter = Math.round(normalizedAngle / 90) * 90;
return quarter;
}
这个函数将任意角度转换为最接近的90度倍数,实现了图片旋转的"磁吸"效果。
二、双击缩放手势实现
1. 双击手势处理逻辑
双击缩放功能是图片预览的常见交互方式,其核心实现如下:
TapGesture({ count: 2 })
.onAction(() => {
const currentScale = this.imageScaleInfo.scaleValue;
const targetScale = currentScale > 1 ? 1 : 2;
runWithAnimation(() => {
this.imageScaleInfo.scaleValue = targetScale;
this.matrix = matrix4.identity()
.scale({
x: targetScale,
y: targetScale
})
.rotate({
x: 0,
y: 0,
z: 1,
angle: this.imageRotateInfo.currentRotate,
}).copy();
})
})
双击缩放的处理逻辑包括:
- 检测当前缩放值,决定是放大还是还原
- 使用动画过渡到目标缩放值
- 保持当前的旋转角度不变
2. 手势冲突处理
在实现多手势组件时,需要注意手势之间的冲突处理:
GestureGroup(GestureMode.Parallel,
TapGesture({ count: 2 })...,
PinchGesture()...,
RotationGesture()...,
PanGesture()...
)
三、完整示例
1. 组件定义
@Component
export struct ImagePreview {
@State private matrix: Matrix4 = matrix4.identity().copy()
private imageRotateInfo: ImageRotateInfo = new ImageRotateInfo()
private imageScaleInfo: ImageScaleInfo = new ImageScaleInfo()
build() {
Image($r('app.media.example'))
.objectFit(ImageFit.Contain)
.gesture(
GestureGroup(GestureMode.Parallel,
// 这里放入之前介绍的所有手势
)
)
.transform(this.matrix)
}
}
2. 效果展示
实现效果如下:
- 支持双指旋转,自动对齐到90度倍数
- 支持双击在1倍和2倍缩放之间切换
- 支持双指缩放和单指拖动
- 所有变换都有平滑动画过渡
四、性能优化建议
矩阵计算优化
- 避免在手势回调中频繁创建新的矩阵对象
- 考虑使用对象池复用矩阵对象
动画性能优化
- 使用requestAnimationFrame代替setTimeout
- 合理设置动画时长,建议在100-300ms之间
内存管理
- 及时清理不再使用的事件监听器
- 合理使用对象池管理频繁创建的对象
五、注意事项
手势阈值设置
- 旋转手势的起始角度阈值建议设置在5-10度之间
- 缩放手势的最小和最大值需要根据实际场景调整
边界处理
- 需要处理图片旋转后的边界情况
- 缩放时需要考虑内存占用,建议限制最大缩放倍数
兼容性处理
- 需要考虑不同设备的屏幕尺寸
- 注意触控板和触摸屏的交互差异
总结
本文详细介绍了HarmonyOS图片预览组件的手势处理实现,包括双指旋转、双击缩放等功能。通过合理的手势配置和动画处理,可以实现流畅的图片预览体验。在实际应用中,还需要根据具体场景进行性能优化和交互细节调整。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。