HarmonyOS7 双指缩放手势:PinchGesture 实现组件放大缩小

📅 2026/7/21 7:54:25 👁️ 阅读次数 📝 编程学习
HarmonyOS7 双指缩放手势:PinchGesture 实现组件放大缩小

文章目录

    • 前言
    • 效果展示
    • 实现原理
      • PinchGesture 的工作方式
      • 缩放计算公式
    • 代码详解
      • 状态变量
      • 缩放组件
      • 重置和放大按钮
      • 完整代码
    • 常见问题
      • Q:缩放有没有极限?
      • Q:能不能只缩放一个方向?
      • Q:fingers 设为 3 能三指缩放吗?
    • 写在最后

前言

双指捏合缩放是触屏设备上最自然的手势之一——打开相册看照片,两指一撑就放大了。ArkUI 用PinchGesture来识别这个手势,提供缩放比例(scale)数据。

今天来实现一个基础的双指缩放效果,并加上重置和按钮放大功能。

效果展示

一个紫色的方块,上面写着"双指缩放"。用户用两根手指捏合或撑开,方块会跟着缩小或放大。方块上方实时显示当前缩放百分比。底部有"重置"和"放大"两个按钮。

实现原理

PinchGesture 的工作方式

PinchGesture检测两根手指之间的距离变化。当两指距离变大(撑开)时,scale> 1(放大);距离变小(捏合)时,scale< 1(缩小)。

初始两指距离 = D0 当前两指距离 = D1 scale = D1 / D0

跟 PanGesture 一样,PinchGesture 的scale也是相对于本次手势起点的相对值。所以在onActionEnd里需要保存当前的缩放值,下次缩放时在这个基础上累乘。

缩放计算公式

当前缩放值 = 上次缩放值 × 本次手势的 scale

代码详解

状态变量

@StatescaleValue:number=1// 当前缩放值@StatelastScale:number=1// 上次手势结束时的缩放值@StatescalePercent:string='100%'// 显示用百分比文本

缩放组件

Column(){Column(){Text('双指缩放').fontSize(18).fontColor('#FFFFFF').margin({bottom:4})Text('Pinch me').fontSize(12).fontColor('#FFFFFF').opacity(0.8)}.width('100%').height('100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).backgroundColor('#9B59B6').borderRadius(16).scale({x:this.scaleValue,y:this.scaleValue}).gesture(PinchGesture({fingers:2}).onActionUpdate((event:GestureEvent)=>{this.scaleValue=this.lastScale*event.scalethis.scalePercent=Math.floor(this.scaleValue*100)+'%'}).onActionEnd(()=>{this.lastScale=this.scaleValue}))}.width(160).height(160)

关键 API:

  • .scale({ x: this.scaleValue, y: this.scaleValue })— 设置组件的缩放比例,X 和 Y 同时缩放保持等比
  • PinchGesture({ fingers: 2 })— 需要两根手指触发
  • event.scale— 本次手势的缩放比例

重置和放大按钮

Row(){Button('重置').width('45%').height(40).backgroundColor('#E0E0E0').borderRadius(10).fontColor('#333333').fontSize(14).onClick(()=>{this.scaleValue=1this.lastScale=1this.scalePercent='100%'})Button('放大').width('45%').height(40).backgroundColor('#9B59B6').borderRadius(10).fontColor('#FFFFFF').fontSize(14).onClick(()=>{this.scaleValue+=0.2this.lastScale=this.scaleValuethis.scalePercent=Math.floor(this.scaleValue*100)+'%'})}.width('100%').justifyContent(FlexAlign.SpaceBetween).margin({top:20})

重置把缩放值恢复到 1(100%),放大按钮每次增加 0.2(20%)。注意修改scaleValue后要同步更新lastScale

完整代码

@Entry@Componentstruct PinchGestureZoom{@StatescaleValue:number=1@StatelastScale:number=1@StatescalePercent:string='100%'build(){Column(){Column(){Text('缩放手势').fontSize(16).fontWeight(FontWeight.Bold).margin({bottom:16})Text(`当前缩放:${this.scalePercent}`).fontSize(18).fontWeight(FontWeight.Bold).fontColor('#4D96FF').margin({bottom:20})Column(){Column(){Text('双指缩放').fontSize(18).fontColor('#FFFFFF').margin({bottom:4})Text('Pinch me').fontSize(12).fontColor('#FFFFFF').opacity(0.8)}.width('100%').height('100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).backgroundColor('#9B59B6').borderRadius(16).scale({x:this.scaleValue,y:this.scaleValue}).gesture(PinchGesture({fingers:2}).onActionUpdate((event:GestureEvent)=>{this.scaleValue=this.lastScale*event.scalethis.scalePercent=Math.floor(this.scaleValue*100)+'%'}).onActionEnd(()=>{this.lastScale=this.scaleValue}))}.width(160).height(160)Row(){Button('重置').width('45%').height(40).backgroundColor('#E0E0E0').borderRadius(10).fontColor('#333333').fontSize(14).onClick(()=>{this.scaleValue=1;this.lastScale=1this.scalePercent='100%'})Button('放大').width('45%').height(40).backgroundColor('#9B59B6').borderRadius(10).fontColor('#FFFFFF').fontSize(14).onClick(()=>{this.scaleValue+=0.2;this.lastScale=this.scaleValuethis.scalePercent=Math.floor(this.scaleValue*100)+'%'})}.width('100%').justifyContent(FlexAlign.SpaceBetween).margin({top:20})}.width('100%').padding(24).backgroundColor('#FFFFFF').borderRadius(12).alignItems(HorizontalAlign.Center)}.width('100%').height('100%').backgroundColor('#F5F6FA').padding(16)}}

常见问题

Q:缩放有没有极限?

默认没有——scale可以无限累乘。实际项目中通常需要限制范围,比如 0.5x 到 3x:

this.scaleValue=Math.max(0.5,Math.min(3,this.lastScale*event.scale))

Q:能不能只缩放一个方向?

可以。.scale({ x: this.scaleValue, y: 1 })就只缩放水平方向,垂直不变。但双指缩放通常是等比缩放,非等比缩放会让内容变形。

Q:fingers 设为 3 能三指缩放吗?

理论上可以,但三指操作在手机上很不方便,不建议使用。

写在最后

PinchGesture让缩放交互变得简单易实现。核心就是lastScale * event.scale的累乘计算,跟 PanGesture 的"上次位置 + 偏移"是同一套思路。

别忘了给缩放加上范围限制,不然用户两指一撑,组件就大到看不全了。