温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦!
Harmonyos NEXT 图片预览组件之手势处理实现(三)
效果预览
一、双击缩放手势实现
在前两篇文章中,我们介绍了图片预览组件的单指拖动、双指缩放和双指旋转手势实现。本文将继续介绍双击缩放手势的实现细节,以及手势之间的协同工作机制。
1. 双击缩放手势定义
TapGesture({ count: 2 })
.onAction(() => {
let fn: Function;
// 当前大小倍数 大于 默认的倍数,则是放大状态需要缩小
if (this.imageScaleInfo.scaleValue > this.imageScaleInfo.defaultScaleValue) {
fn = () => {
// 恢复默认大小
this.imageScaleInfo.reset();
// 重置偏移量
this.imageOffsetInfo.reset();
// 设置一个新的矩阵
this.matrix = matrix4.identity().copy().rotate({
z: 1,
angle: this.imageRotateInfo.lastRotate
});
}
} else {
fn = () => {
// 这里是正常状态 -- 需要放大
// 获取放大倍数
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,
}).rotate({
z: 1,
angle: this.imageRotateInfo.lastRotate
}).copy();
// 设置最后放大倍数设置为当前的倍数
this.imageScaleInfo.stash();
}
}
runWithAnimation(fn);
})
2. 双击缩放处理逻辑
双击缩放手势的核心逻辑包括:
判断当前图片的缩放状态:
- 如果当前缩放值大于默认值(已放大状态),则执行缩小操作
- 如果当前缩放值等于默认值(未放大状态),则执行放大操作
缩小操作:
- 重置缩放值为默认值
- 重置偏移量为0
- 应用矩阵变换,保持当前旋转角度
放大操作:
- 计算适合屏幕的缩放比例
- 设置缩放值为计算得到的比例
- 重置偏移量为0
- 应用矩阵变换,结合缩放和旋转
- 保存当前缩放值为最后缩放值
- 使用动画效果执行缩放操作,提供平滑的视觉体验
3. 适配屏幕的缩放比例计算
calcFitScaleRatio(imageSize: image.Size, windowSize: window.Size): number {
let ratio: number = 1.0;
if (windowSize.width > imageSize.width) {
ratio = windowSize.width / imageSize.width;
} else {
ratio = windowSize.height / imageSize.height;
}
return ratio;
}
这个方法计算图片适配屏幕的缩放比例,确保图片能够填满屏幕。计算逻辑如下:
- 如果窗口宽度大于图片宽度,则以宽度为基准计算缩放比例
- 否则,以高度为基准计算缩放比例
二、手势组合与协同工作
1. 手势组合实现
图片预览组件使用GestureGroup将多种手势组合在一起,实现复杂的交互效果:
.gesture(
GestureGroup(
GestureMode.Parallel,
// 双击切换图片大小
TapGesture({ count: 2 }),
// 拖动图片
PanGesture({ fingers: 1 })
)
)
// 两根手指操作
.gesture(
GestureGroup(
GestureMode.Parallel,
// 双指旋转图片
RotationGesture({ angle: this.imageRotateInfo.startAngle }),
// 双指缩放图片
PinchGesture({ fingers: 2, distance: 1 })
)
)
组件将手势分为两组:
- 单指手势组:包含双击手势和单指拖动手势
- 双指手势组:包含旋转手势和缩放手势
通过GestureMode.Parallel模式,允许同一组内的手势并行识别和处理,提供更自然的交互体验。
2. 手势状态协同
不同手势之间通过共享数据模型实现状态协同:
// 图片旋转信息
@State imageRotateInfo: RotateModel = new RotateModel();
// 图片缩放信息
@State imageScaleInfo: ScaleModel = new ScaleModel(1.0, 1.0, 1.5, 0.3);
// 图片偏移信息
@State imageOffsetInfo: OffsetModel = new OffsetModel(0, 0);
这些状态模型在不同手势之间共享,确保手势操作的一致性和连贯性:
- 旋转手势更新imageRotateInfo
- 缩放手势更新imageScaleInfo
- 拖动手势更新imageOffsetInfo
3. 矩阵变换的统一应用
所有手势操作最终都通过matrix4矩阵变换应用到图片上:
// 本模块提供矩阵变换功能,可对图形进行平移、旋转和缩放等
@State matrix: matrix4.Matrix4Transit = matrix4.identity().copy();
// 应用矩阵变换
Image(this.imageUrl)
.transform(this.matrix)
.offset({
x: this.imageOffsetInfo.currentX,
y: this.imageOffsetInfo.currentY
})
矩阵变换和偏移量的组合使用,实现了图片的复合变换效果:
- 矩阵变换(matrix):实现缩放和旋转
- 偏移量(offset):实现位移
三、手势边界处理
1. 缩放边界处理
// 当小于默认大小时,恢复为默认大小
if (this.imageScaleInfo.scaleValue < this.imageScaleInfo.defaultScaleValue) {
runWithAnimation(() => {
this.imageScaleInfo.reset();
this.imageOffsetInfo.reset();
this.matrix = matrix4.identity().rotate({
x: 0,
y: 0,
z: 1,
angle: this.imageRotateInfo.currentRotate,
}).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
}).rotate({
x: 0,
y: 0,
z: 1,
angle: this.imageRotateInfo.currentRotate,
});
})
}
缩放边界处理确保图片的缩放值在合理范围内,并在超出范围时平滑恢复。
2. 旋转边界处理
let rotate = simplestRotationQuarter(this.imageRotateInfo.currentRotate);
runWithAnimation(() => {
this.imageRotateInfo.currentRotate = rotate;
// 应用旋转变换
})
旋转边界处理将旋转角度对齐到最接近的90度倍数,提供更整齐的视觉效果。
3. 拖动边界处理
evaluateBound(): void {
const xBol = constrainOffsetAndAnimation({
dimensionWH: ImageFitType.TYPE_WIDTH,
// 其他参数...
});
const yBol = constrainOffsetAndAnimation({
dimensionWH: ImageFitType.TYPE_HEIGHT,
// 其他参数...
});
// 处理边界情况...
}
拖动边界处理确保图片不会被拖出视口,并在达到边界时触发图片切换。
四、总结
图片预览组件的手势处理实现了丰富的交互功能,包括单指拖动、双指缩放、双指旋转和双击缩放等。通过合理的手势组合和状态协同,提供了流畅自然的用户体验。
手势处理的核心技术包括:
- 使用GestureGroup组合多种手势,实现复杂交互
- 通过数据模型共享状态,确保手势操作的一致性
- 使用matrix4矩阵变换实现图片的复合变换
- 通过边界处理确保交互操作的合理性
- 添加动画效果提供平滑的视觉体验
这些技术的综合应用,使图片预览组件能够提供接近原生应用的交互体验,满足用户对图片预览的各种需求。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。