HarmonyOS7 双指缩放手势:PinchGesture 实现组件放大缩小
📅 2026/7/21 7:54:25
👁️ 阅读次数
📝 编程学习
文章目录
- 前言
- 效果展示
- 实现原理
- 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 的"上次位置 + 偏移"是同一套思路。
别忘了给缩放加上范围限制,不然用户两指一撑,组件就大到看不全了。
编程学习
技术分享
实战经验