温馨提示:本篇博客的详细代码已发布到 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();
        })
    })

旋转手势的处理逻辑包括:

  1. 设置触发旋转的最小角度阈值(startAngle),防止误触
  2. 根据event.angle计算新的旋转角度,基于上次旋转的结果(lastRotate)
  3. 应用矩阵变换,实现图片的旋转效果
  4. 手势结束时,将旋转角度对齐到最接近的90度倍数(0°、90°、180°、270°)
  5. 保存当前旋转角度为最后旋转角度,用于下次旋转的基准计算

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();
        })
    })

双击缩放的处理逻辑包括:

  1. 检测当前缩放值,决定是放大还是还原
  2. 使用动画过渡到目标缩放值
  3. 保持当前的旋转角度不变

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倍缩放之间切换
  • 支持双指缩放和单指拖动
  • 所有变换都有平滑动画过渡

四、性能优化建议

  1. 矩阵计算优化

    • 避免在手势回调中频繁创建新的矩阵对象
    • 考虑使用对象池复用矩阵对象
  2. 动画性能优化

    • 使用requestAnimationFrame代替setTimeout
    • 合理设置动画时长,建议在100-300ms之间
  3. 内存管理

    • 及时清理不再使用的事件监听器
    • 合理使用对象池管理频繁创建的对象

五、注意事项

  1. 手势阈值设置

    • 旋转手势的起始角度阈值建议设置在5-10度之间
    • 缩放手势的最小和最大值需要根据实际场景调整
  2. 边界处理

    • 需要处理图片旋转后的边界情况
    • 缩放时需要考虑内存占用,建议限制最大缩放倍数
  3. 兼容性处理

    • 需要考虑不同设备的屏幕尺寸
    • 注意触控板和触摸屏的交互差异

总结

本文详细介绍了HarmonyOS图片预览组件的手势处理实现,包括双指旋转、双击缩放等功能。通过合理的手势配置和动画处理,可以实现流畅的图片预览体验。在实际应用中,还需要根据具体场景进行性能优化和交互细节调整。


全栈若城
1 声望1 粉丝