HarmonyOS 鸿蒙Next手势旋转
HarmonyOS 鸿蒙Next手势旋转 大佬们,求个简单的手势旋转的Demo
4 回复
【背景知识】
- 通用属性transform可以设置组件的变换矩阵。
- PanGesture滑动手势事件,当滑动的最小距离达到设定的最小值时触发滑动手势事件。
- [@ohos.matrix4](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-matrix4)模块提供矩阵变换功能,支持对图形进行平移、旋转和缩放等。
【解决方案】
这边旋转的场景是什么,可以参考下这个demo,通过手势对组件进行旋转这样:
import { matrix4 } from '@kit.ArkUI'
@Entry
@ComponentV2
struct ImageMovePage {
// 声明平移矩阵
@Local matrix: matrix4.Matrix4Transit = matrix4.identity().copy();
// 声明旋转矩阵
@Local translateMatrix: matrix4.Matrix4Transit = matrix4.identity().copy();
// 声明手势前的矩阵
private rotateAndScaleMatrix: matrix4.Matrix4Transit = matrix4.identity().copy();
// 声明初始位置坐标
private initStackX: number = 0;
private initStackY: number = 0;
// 声明初始宽高
private initStackWidth: number = 0;
private initStackHeight: number = 0;
// 声明中心点坐标
private initCenterX: number = 0;
private initCenterY: number = 0;
// 声明初始半径
private initR: number = 0;
// 声明初始角度
private initAngle: number = 0;
// 声明手势开始时的坐标
private startStackX: number = 0;
private startStackY: number = 0;
// 声明当前位置
@Local currentX: number = 0;
@Local currentY: number = 0;
// 声明当前中心点坐标
@Local currentCenterX: number = 0;
@Local currentCenterY: number = 0;
// 声明缩放比例
@Local stackScale: number = 1;
private lastScale: number = 1;
// 声明当前旋转角度
@Local stackRotate: number = 0;
private lastRotate: number = 0;
// 声明移动时手指的初始坐标
private initFingerX: number = -1;
private initFingerY: number = -1;
private lastFingerX: number = 0;
private lastFingerY: number = 0;
// 在即将出现时初始化数据
aboutToAppear(): void {
this.init();
}
// 初始化方法:获取初始位置
init() {
let observer = this.getUIContext().getUIInspector().createComponentObserver('target');
observer.on('layout', () => {
let node = this.getUIContext().getAttachedFrameNodeById('target');
if (node) {
let position = node.getPositionToParent();
this.initStackX = position.x;
this.initStackY = position.y;
let size = node.getMeasuredSize();
this.initStackWidth = this.getUIContext().px2vp(size.width);
this.initStackHeight = this.getUIContext().px2vp(size.height);
this.initCenterX = this.initStackX + (this.initStackWidth >> 1);
this.initCenterY = this.initStackY + (this.initStackHeight >> 1);
this.initR = Math.sqrt((this.initStackWidth >> 1) * (this.initStackWidth >> 1) +
(this.initStackHeight >> 1) * (this.initStackHeight >> 1));
this.initAngle = Math.atan2((this.initStackHeight), (this.initStackWidth)) * 180 / Math.PI;
}
console.info('on layout:',
`x:${this.initStackX}, y:${this.initStackY}, width: ${this.initStackWidth}, height: ${this.initStackHeight}, centerX: ${this.initCenterX}, centerY: ${this.initCenterY}
initR: ${this.initR}, angle: ${this.initAngle}
`)
observer.off('layout');
})
}
build() {
NavDestination() {
Stack() {
Stack() {
Stack({ alignContent: Alignment.BottomEnd }) {
Text('harmonyos')
.width(180)
.height(180)
.borderWidth(1)
.borderColor('#f00')
.fontColor('#fff')
Text()
.width(60)
.height(60)
.backgroundColor('#0f0')
.gesture(
PanGesture()
.onActionStart(event => {
// 记录上一次的矩阵
this.rotateAndScaleMatrix = this.matrix.copy();
// 获取手指位置
this.initFingerX = (this.initStackWidth >> 1);
this.initFingerY = (this.initStackHeight >> 1);
})
.onActionUpdate(event => {
// 获取当前坐标手指
let currentFingerX: number = this.initFingerX + event.offsetX;
let currentFingerY: number = this.initFingerY + event.offsetY;
// 映射手指坐标
let point = this.rotateAndScaleMatrix.copy().transformPoint([currentFingerX, currentFingerY]);
currentFingerX = point[0];
currentFingerY = point[1];
console.info('event.offsetX:', currentFingerX, 'event.offsetY', currentFingerY);
// 获取半径
let r: number = Math.sqrt(currentFingerX * currentFingerX + currentFingerY * currentFingerY);
console.info('半径r:', r, '初始半径:', this.initR, '比率:', r / this.initR);
// 获取cos和sin,判断象限
this.stackScale = (r / this.initR);
// 声明角度
let theta: number = Math.atan2(currentFingerY, currentFingerX) * 180 / Math.PI - this.initAngle;
// 判断象限
this.stackRotate = theta;
this.matrix = matrix4.identity().copy()
// .scale({ x: r / this.initR, y: r / this.initR })
.rotate({ z: 1, angle: theta })
})
.onActionEnd(event => {
// this.lastFingerX = this.initFingerX + event.offsetX;
// this.lastFingerY = this.initFingerY + event.offsetY;
console.info('旋转角度:', this.stackRotate);
})
)
}
.transform(this.matrix).gesture(
PanGesture()
.onActionStart(() => {
this.startStackX = this.currentX;
this.startStackY = this.currentY;
})
.onActionUpdate(event => {
// 获取手指位置
let point = this.matrix.copy().transformPoint([event.offsetX, event.offsetY]);
this.currentX = this.startStackX + point[0];
this.currentY = this.startStackY + point[1];
})
.onActionEnd(() => {
console.info('currentX:', this.currentX, 'currentY:', this.currentY);
})
)
}
.id('target')
}
.height('100%')
.backgroundColor('#000')
.width('100%')
}
}
}
如果是需要双指旋转手势,可以参考官网示例,可以根据实际需要进行具体开发。
更多关于HarmonyOS 鸿蒙Next手势旋转的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
6啊,
HarmonyOS Next的手势旋转功能基于ArkTS/ArkUI框架实现。通过RotationGesture组件的onAction回调可获取旋转角度与速度,使用rotate方法直接操作组件旋转属性。系统自动处理多指触摸数据,识别旋转手势并触发响应。开发者需在布局中声明RotationGesture识别器,绑定旋转事件处理逻辑。该功能依赖鸿蒙的分布式手势识别能力,支持跨设备同步旋转状态。
基于HarmonyOS Next的手势旋转简单Demo实现
使用ArkTS编写,适用于旋转图片或组件:
import { Gesture, GestureGroup, GestureMask, PanGesture, RotationGesture } from '@kit.ArkUI';
@Entry
@Component
struct RotationDemo {
@State angle: number = 0; // 旋转角度
private initialAngle: number = 0; // 初始角度记录
build() {
Column() {
// 可旋转的图片组件
Image($r('app.media.rotate_img'))
.width(200)
.height(200)
.rotate({ angle: this.angle })
// 组合手势:旋转+平移(可选)
.gesture(
GestureGroup(
GestureMode.Exclusive,
RotationGesture()
.onActionStart((event: GestureEvent) => {
this.initialAngle = this.angle; // 记录开始角度
})
.onActionUpdate((event: RotationGestureEvent) => {
// 更新旋转角度(弧度转角度)
this.angle = this.initialAngle + event.angle * 180 / Math.PI;
}),
PanGesture({ distance: 1 }) // 可同时支持平移
)
)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
关键说明
- 使用
RotationGesture监听旋转手势 - 通过
rotate修饰符实时更新组件旋转角度 GestureMode.Exclusive保证多手势互斥识别- 角度计算:手势返回弧度值,需转换为角度(1弧度≈57.3度)
扩展建议
- 可搭配
PinchGesture实现缩放组合手势 - 通过
onActionEnd添加旋转惯性动画 - 使用
GestureMask.Normal控制手势竞争关系
此Demo实现了基础旋转功能,实际使用时需替换图片资源路径并调整手势参数。

