HarmonyOS7 旋转手势:RotationGesture 实现双指旋转组件

HarmonyOS7 旋转手势:RotationGesture 实现双指旋转组件

文章目录

    • 前言
    • 效果展示
    • 实现原理
      • RotationGesture 的工作方式
      • 旋转的渲染
    • 代码详解
      • 状态变量
      • 可旋转的组件
      • 角度显示与重置
      • 完整代码
    • 进阶技巧
      • 角度吸附
      • 限制旋转范围
      • 旋转 + 缩放组合
    • 写在最后

前言

旋转手势在各种创意类 App 中很常见——照片编辑器里旋转图片、地图里旋转视角、游戏中旋转道具。ArkUI 提供了RotationGesture来检测双指旋转,返回旋转角度。

今天来实现一个可旋转的组件,实时显示旋转角度,并支持重置。

效果展示

一个橙色的正方形,里面有十字线和旋转图标。用户用两根手指旋转,方块跟着旋转。上方实时显示当前旋转角度。底部有"重置角度"按钮。

实现原理

RotationGesture 的工作方式

RotationGesture检测两根手指连线的角度变化。当两根手指的连线从水平变成倾斜时,event.angle就是旋转的角度值(正值顺时针,负值逆时针)。

跟 PanGesture 和 PinchGesture 一样,event.angle是相对于本次手势起点的相对值,需要累加。

当前角度 = 上次角度 + 本次手势的 angle

旋转的渲染

ArkUI 的.rotate()属性用来旋转组件:

.rotate({angle:this.angle})

angle正值表示顺时针旋转,单位是度(degree)。

代码详解

状态变量

@Stateangle:number=0@StatelastAngle:number=0

两个变量:当前显示角度和上次手势结束时的角度。

可旋转的组件

Column(){Stack(){Column(){}.width(4).height(60).backgroundColor('#FFFFFF')Column(){}.width(60).height(4).backgroundColor('#FFFFFF')Column(){Text('⟳').fontSize(30).fontColor('#FFFFFF')}.offset({x:0,y:-40})}}.width(140).height(140).backgroundColor('#FFA500').borderRadius(20).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).rotate({angle:this.angle}).gesture(RotationGesture({fingers:2}).onActionUpdate((event:GestureEvent)=>{this.angle=this.lastAngle+event.angle}).onActionEnd(()=>{this.lastAngle=this.angle}))

方块内部用两个细长的白色矩形交叉形成十字线,加上一个旋转符号,视觉上暗示"可以旋转"。

.rotate({ angle: this.angle })让整个方块按当前角度旋转。旋转是围绕组件中心点进行的。

角度显示与重置

Text(`旋转角度:${Math.floor(this.angle)}°`).fontSize(18).fontWeight(FontWeight.Bold).fontColor('#4D96FF').margin({bottom:24})Button('重置角度').width('100%').height(42).backgroundColor('#E0E0E0').borderRadius(10).fontColor('#333333').fontSize(15).margin({top:20}).onClick(()=>{this.angle=0this.lastAngle=0})

Math.floor取整显示角度,避免小数位看着乱。重置按钮把两个状态变量都清零。

完整代码

@Entry@Componentstruct RotationGesturePage{@Stateangle:number=0@StatelastAngle:number=0build(){Column(){Column(){Text('旋转手势').fontSize(16).fontWeight(FontWeight.Bold).margin({bottom:16})Text(`旋转角度:${Math.floor(this.angle)}°`).fontSize(18).fontWeight(FontWeight.Bold).fontColor('#4D96FF').margin({bottom:24})Column(){Stack(){Column(){}.width(4).height(60).backgroundColor('#FFFFFF')Column(){}.width(60).height(4).backgroundColor('#FFFFFF')Column(){Text('⟳').fontSize(30).fontColor('#FFFFFF')}.offset({x:0,y:-40})}}.width(140).height(140).backgroundColor('#FFA500').borderRadius(20).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).rotate({angle:this.angle}).gesture(RotationGesture({fingers:2}).onActionUpdate((event:GestureEvent)=>{this.angle=this.lastAngle+event.angle}).onActionEnd(()=>{this.lastAngle=this.angle}))Button('重置角度').width('100%').height(42).backgroundColor('#E0E0E0').borderRadius(10).fontColor('#333333').fontSize(15).margin({top:20}).onClick(()=>{this.angle=0;this.lastAngle=0})}.width('100%').padding(24).backgroundColor('#FFFFFF').borderRadius(12).alignItems(HorizontalAlign.Center)}.width('100%').height('100%').backgroundColor('#F5F6FA').padding(16)}}

进阶技巧

角度吸附

让角度在接近 0°、90°、180°、270° 时自动吸附:

.onActionEnd(()=>{this.lastAngle=this.angleconstsnapped=Math.round(this.angle/90)*90if(Math.abs(this.angle-snapped)<10){animateTo({duration:200},()=>{this.angle=snappedthis.lastAngle=snapped})}})

当角度距离 90 的整数倍不超过 10 度时,自动吸附到整数值。

限制旋转范围

如果只需要 0-360 度的范围:

.onActionUpdate((event:GestureEvent)=>{letnewAngle=this.lastAngle+event.anglethis.angle=((newAngle%360)+360)%360})

用取模运算把角度限制在 0-360 范围内。

旋转 + 缩放组合

GestureGroup同时支持旋转和缩放:

.gesture(GestureGroup(GestureMode.Parallel,RotationGesture({fingers:2}).onActionUpdate((event)=>{this.angle=this.lastAngle+event.angle}).onActionEnd(()=>{this.lastAngle=this.angle}),PinchGesture({fingers:2}).onActionUpdate((event)=>{this.scale=Math.max(0.5,Math.min(3,this.lastScale*event.scale))}).onActionEnd(()=>{this.lastScale=this.scale})))

GestureMode.Parallel允许两个手势同时识别——用户一边旋转一边缩放,两个效果叠加。

写在最后

RotationGesture是 ArkUI 手势家族中最"酷"的一个。双指旋转的操作方式直觉且有趣。.rotate()属性配合手势回调,几行代码就能实现流畅的旋转效果。

旋转手势最常见的应用是图片编辑和地图,配合缩放和拖拽,就能实现一个功能完整的画布操作。