本文将详细介绍如何在HarmonyOS应用中实现图片的放大、缩小以及拖拽移动功能,并在此基础上增加图片翻页功能。我们将使用HarmonyOS提供的GestureGroup
来组合PinchGesture
(捏合手势)和PanGesture
(滑动手势),以达到所需的交互效果。
核心功能实现
步骤1:绑定组合手势
首先,我们需要定义一个组合手势GestureGroup
,并将其设置为并行识别模式。这样,我们可以同时监听捏合手势和滑动手势。
@Styles
onImageGesture() {
return .gesture(
GestureGroup(GestureMode.Parallel,
// 双指捏合手势
PinchGesture({ fingers: 2, distance: 0.1 })
.onActionUpdate((event: GestureEvent) => {
this.onPinchGestureActionUpdate(event);
})
.onActionEnd(() => {
this.onPinchGestureActionEnd();
}),
// 拖动手势
PanGesture(this.panOption)
.onActionUpdate((event?: GestureEvent) => {
this.onPanGestureActionUpdate(event);
})
.onActionEnd(() => {
this.onPanGestureActionEnd();
})
)
);
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
步骤2:处理捏合手势
接下来,我们定义捏合手势的更新和结束回调,以便处理图片的缩放。
onPinchGestureActionUpdate(event: GestureEvent) {
const SCALE_VALUE = this.pinchValue * event.scale;
if (SCALE_VALUE <= this.imageMeta.MAX_SCALE_VALUE && SCALE_VALUE >= this.MIN_SCALE) {
this.scaleValue = SCALE_VALUE;
this.pinchX = event.pinchCenterX;
this.pinchY = this.getPinchY(event.pinchCenterY);
if (this.scaleValue > 1) {
this.offsetX = 0;
}
}
}
getPinchY(pinchCenterY: number | string) {
let pinchY = pinchCenterY;
if (this.scaleValue > 1) {
// 当为横图时,在留白处放大,图片位置不居中,手动计算pinchY,并移动Y轴中心点,即offsetY
if (this.imageMeta.IMAGE_WIDTH >= this.imageMeta.IMAGE_HEIGHT) {
const SCREEN_HEIGHT = px2vp(display.getDefaultDisplaySync().height);
const MIN_PINCH_Y = SCREEN_HEIGHT / 2 - this.imageMeta.IMAGE_HEIGHT / 2;
const MAX_PINCH_Y = SCREEN_HEIGHT / 2 + this.imageMeta.IMAGE_HEIGHT / 2;
const MIDDLE_PINCH_Y = SCREEN_HEIGHT / 2;
if (pinchY < MIN_PINCH_Y) {
pinchY = MIN_PINCH_Y;
}
if (pinchY > MAX_PINCH_Y) {
pinchY = MAX_PINCH_Y;
}
if (pinchY < MIDDLE_PINCH_Y && typeof this.pinchY === 'number') {
this.offsetY = (Number(pinchY) - MIDDLE_PINCH_Y) * (this.scaleValue - 1);
}
if (pinchY > MIDDLE_PINCH_Y && typeof this.pinchY === 'number') {
this.offsetY = (Number(pinchY) - MIDDLE_PINCH_Y) * (this.scaleValue - 1);
}
}
}
return pinchY;
}
onPinchGestureActionEnd() {
this.pinchValue = this.scaleValue;
if (this.pinchValue > 1) {
this.scaleEnable();
} else {
this.scaleUnEnable();
if (this.pinchValue < 1) {
this.reset();
}
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
步骤3:处理滑动手势
滑动手势需要处理图片的拖拽移动,包括边界检测。
onPanGestureActionUpdate(event: GestureEvent) {
if (!event || this.scaleValue <= 1) {
return;
}
let boundaryOffset: BoundaryOffset = {
left: 0,
right: 0,
top: 0,
bottom: 0
};
this.xBoundary = HorizontalBoundary.MIDDLE;
this.yBoundary = VerticalBoundary.MIDDLE;
const CENTER_X_RELATIVE = typeof this.pinchX === 'number' ? this.pinchX / this.imageMeta.IMAGE_WIDTH : 0.5;
boundaryOffset.left = this.imageMeta.IMAGE_WIDTH * (this.scaleValue - 1) * CENTER_X_RELATIVE;
boundaryOffset.right = -this.imageMeta.IMAGE_WIDTH * (this.scaleValue - 1) * (1 - CENTER_X_RELATIVE);
const NEWOFFSET_X = this.positionX + event.offsetX;
// 更新x轴偏移位置
if (NEWOFFSET_X <= boundaryOffset.left && NEWOFFSET_X >= boundaryOffset.right) {
// 在中间
this.offsetX = NEWOFFSET_X;
} else {
// 在边界
if (this.fingerDirection === FingerDirection.LEFT && this.offsetX !== boundaryOffset.right) {
this.offsetX = boundaryOffset.right;
}
if (this.fingerDirection === FingerDirection.RIGHT && this.offsetX !== boundaryOffset.left) {
this.offsetX = boundaryOffset.left;
}
}
// 在左边界
if (NEWOFFSET_X >= boundaryOffset.left) {
this.xBoundary = HorizontalBoundary.LEFT;
}
// 在右边界
if (NEWOFFSET_X <= boundaryOffset.right) {
this.xBoundary = HorizontalBoundary.RIGHT;
}
if (this.imageMeta.PAN_DIRECTION === PanDirection.All || this.imageMeta.PAN_DIRECTION === PanDirection.Vertical||this.imageMeta.PAN_DIRECTION === PanDirection.Horizontal) {
// 更新y轴偏移量
const NEWOFFSET_Y = this.positionY + event.offsetY;
this.offsetY = NEWOFFSET_Y;
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
步骤4:处理图片翻页
最后,我们需要实现图片翻页的功能。这涉及到检测边界上的手势方向,以确定是否应该翻页。
@Styles
onImageTouch() {
return .onTouch((event: TouchEvent) => {
if (this.scaleValue > 1) {
if (event.type === TouchType.Down) {
this.touchPos.x = event.touches[0].x;
this.touchPos.y = event.touches[0].y;
}
if (event.type === TouchType.Move) {
this.fingerDirection = getMoveFingerDirection(this.touchPos, event, this.fingerDirection);
if (!isPageChangeOnBoundary(this.fingerDirection, this.xBoundary)) {
if (!this.isScaling) {
this.touchFlag = 1;
this.scaleEnable();
this.xBoundary = HorizontalBoundary.MIDDLE;
this.temp = this.offsetX;
this.tempY = this.offsetY;
}
}
}
if (event.type === TouchType.Up) {
if (this.touchFlag == 1) {
this.onPanGestureActionEnd();
}
this.touchFlag = 0;
this.temp = 0;
this.tempY = 0;
if (isPageChangeOnBoundary(this.fingerDirection, this.xBoundary) || this.scaleValue === 1) {
this.scaleUnEnable();
} else {
this.scaleEnable();
}
}
}
});
}
// 拖动,不翻页
scaleEnable() {
if (this.isScaling) {
return;
}
this.panOption.setDirection(this.imageMeta.PAN_DIRECTION);
this.isScaling = true;
}
// 不能拖动,翻页
scaleUnEnable() {
if (!this.isScaling) {
return;
}
this.panOption.setDirection(PanDirection.None);
this.isScaling = false;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
步骤5:边界检测与翻页判断
我们还需要定义一个辅助方法来判断是否在边界上进行翻页。
总结
通过上述步骤,我们成功实现了图片的放大、缩小、拖拽移动以及翻页功能。这些功能可以极大地提升用户的交互体验。希望本指南能帮助你在HarmonyOS应用中实现这些功能。