1# PinchGesture 2<!--Kit: ArkUI--> 3<!--Subsystem: ArkUI--> 4<!--Owner: @jiangtao92--> 5<!--Designer: @piggyguy--> 6<!--Tester: @songyanhong--> 7<!--Adviser: @HelloCrease--> 8 9**PinchGesture** is used to trigger a pinch gesture, which requires two to five fingers with a minimum 5 vp distance between the fingers. 10 11> **NOTE** 12> 13> This gesture is supported since API version 7. Updates will be marked with a superscript to indicate their earliest API version. 14> 15> After a pinch gesture is successfully triggered, all fingers must be lifted and pressed again to trigger the pinch gesture again. 16 17 18## APIs 19 20### PinchGesture 21 22PinchGesture(value?: { fingers?: number, distance?: number }) 23 24Sets the parameters for the pinch gesture. 25 26**Atomic service API**: This API can be used in atomic services since API version 11. 27 28**System capability**: SystemCapability.ArkUI.ArkUI.Full 29 30**Parameters** 31 32| Name| Type| Mandatory| Description| 33| -------- | -------- | -------- | -------- | 34| value | { fingers?: number, distance?: number } | No| Parameters for the pinch gesture.<br> - **fingers**: minimum number of fingers to trigger a pinch. The value ranges from 2 to 5.<br>Default value: **2**<br>While more fingers than the minimum number can be pressed to trigger the gesture, only the first fingers of the minimum number participate in gesture calculation.<br> - **distance**: minimum recognition distance, in vp.<br>Default value: **5**<br>**NOTE**<br>Value range: [0, +∞). If the value is less than or equal to 0, it will be converted to the default value.| 35 36### PinchGesture<sup>15+</sup> 37 38PinchGesture(options?: PinchGestureHandlerOptions) 39 40Sets the parameters for the pinch gesture. Compared with [PinchGesture](#pinchgesture-1), this API adds the **isFingerCountLimited** parameter to **options**, which determines whether to enforce the exact number of fingers touching the screen. 41 42**Atomic service API**: This API can be used in atomic services since API version 15. 43 44**System capability**: SystemCapability.ArkUI.ArkUI.Full 45 46**Parameters** 47 48| Name| Type| Mandatory| Description| 49| -------- | -------- | -------- | -------- | 50| options | [PinchGestureHandlerOptions](./ts-uigestureevent.md#pinchgesturehandleroptions) | No| Parameters of the pinch gesture handler.| 51 52 53## Events 54 55> **NOTE** 56> 57> In **fingerList** of [GestureEvent](ts-gesture-settings.md#gestureevent), the index of a finger corresponds to its position, that is, the ID of a finger in **fingerList[index]** refers to its index. If a finger is pressed first and does not participate in triggering of the current gesture, its position in **fingerList** is left empty. You are advised to use **fingerInfos** when possible. 58 59### onActionStart 60 61onActionStart(event: (event: GestureEvent) => void) 62 63Triggered when a pinch gesture is recognized. 64 65**Atomic service API**: This API can be used in atomic services since API version 11. 66 67**System capability**: SystemCapability.ArkUI.ArkUI.Full 68 69**Parameters** 70 71| Name| Type | Mandatory| Description | 72| ------ | ------------------------------------------ | ---- | ---------------------------- | 73| event | (event: [GestureEvent](ts-gesture-settings.md#gestureevent)) => void | Yes | Callback for the pinch event.| 74 75### onActionUpdate 76 77onActionUpdate(event: (event: GestureEvent) => void) 78 79Triggered when the user moves the finger in the pinch gesture on the screen. 80 81**Atomic service API**: This API can be used in atomic services since API version 11. 82 83**System capability**: SystemCapability.ArkUI.ArkUI.Full 84 85**Parameters** 86 87| Name| Type | Mandatory| Description | 88| ------ | ------------------------------------------ | ---- | ---------------------------- | 89| event | (event: [GestureEvent](ts-gesture-settings.md#gestureevent)) => void | Yes | Callback for the pinch event.| 90 91### onActionEnd 92 93onActionEnd(event: (event: GestureEvent) => void) 94 95Triggered when the fingers used for the pinch gesture are lifted. 96 97**Atomic service API**: This API can be used in atomic services since API version 11. 98 99**System capability**: SystemCapability.ArkUI.ArkUI.Full 100 101**Parameters** 102 103| Name| Type | Mandatory| Description | 104| ------ | ------------------------------------------ | ---- | ---------------------------- | 105| event | (event: [GestureEvent](ts-gesture-settings.md#gestureevent)) => void | Yes | Callback for the pinch event.| 106 107### onActionCancel 108 109onActionCancel(event: () => void) 110 111Triggered when a tap cancellation event is received after the pinch gesture is recognized. Gesture event information is returned. 112 113**Atomic service API**: This API can be used in atomic services since API version 11. 114 115**System capability**: SystemCapability.ArkUI.ArkUI.Full 116 117**Parameters** 118 119| Name| Type | Mandatory| Description | 120| ------ | ------------------------------------------ | ---- | ---------------------------- | 121| event | () => void | Yes | Callback for the pinch event.| 122 123### onActionCancel<sup>18+</sup> 124 125onActionCancel(event: Callback\<GestureEvent\>) 126 127Triggered when a tap cancellation event is received after the pinch gesture is recognized. Gesture event information is returned. 128 129**Atomic service API**: This API can be used in atomic services since API version 18. 130 131**System capability**: SystemCapability.ArkUI.ArkUI.Full 132 133**Parameters** 134 135| Name| Type | Mandatory| Description | 136| ------ | ------------------------------------------ | ---- | ---------------------------- | 137| event | Callback\<[GestureEvent](ts-gesture-settings.md#gestureevent)> | Yes | Callback for the pinch event.| 138 139## Attributes 140 141**System capability**: SystemCapability.ArkUI.ArkUI.Full 142 143| Name| Type | Read-Only| Optional| Description | 144| ---- | ------| -----| -----|----------------------------------- | 145| tag<sup>12+</sup> | string | No| No| Tag for the pinch gesture. It is used to distinguish the gesture during custom gesture recognition.<br>**Atomic service API**: This API can be used in atomic services since API version 12.| 146| allowedTypes<sup>14+</sup> | No| No| Array\<[SourceTool](ts-gesture-settings.md#sourcetool9)> | Allowed event input types for the pinch gesture.<br>**Atomic service API**: This API can be used in atomic services since API version 14.| 147 148## Example 149 150### Example 1: Implementing Simple Scaling 151 152This example demonstrates the recognition of a three-finger pinch gesture using **PinchGesture**. 153 154```ts 155// xxx.ets 156@Entry 157@Component 158struct PinchGestureExample { 159 @State scaleValue: number = 1; 160 @State pinchValue: number = 1; 161 @State pinchX: number = 0; 162 @State pinchY: number = 0; 163 164 build() { 165 Column() { 166 Column() { 167 Text('PinchGesture scale:\n' + this.scaleValue) 168 Text('PinchGesture center:\n(' + this.pinchX + ',' + this.pinchY + ')') 169 } 170 .height(200) 171 .width(300) 172 .padding(20) 173 .border({ width: 3 }) 174 .margin({ top: 100 }) 175 .scale({ x: this.scaleValue, y: this.scaleValue, z: 1 }) 176 // The gesture event is triggered by pinching three fingers together. 177 .gesture( 178 PinchGesture({ fingers: 3 }) 179 .onActionStart((event: GestureEvent) => { 180 console.info('Pinch start') 181 }) 182 .onActionUpdate((event: GestureEvent) => { 183 if (event) { 184 this.scaleValue = this.pinchValue * event.scale 185 this.pinchX = event.pinchCenterX 186 this.pinchY = event.pinchCenterY 187 } 188 }) 189 .onActionEnd((event: GestureEvent) => { 190 this.pinchValue = this.scaleValue 191 console.info('Pinch end') 192 }) 193 ) 194 }.width('100%') 195 } 196} 197``` 198 199  200 201### Example 2: Implementing Image Scaling with Finger Tracking 202 203This example demonstrates how to implement image scaling with finger tracking by configuring **PinchGesture**. 204 205```ts 206// xxx.ets 207import { UIContext, display, matrix4 } from '@kit.ArkUI'; 208 209@Entry 210@Component 211struct PinchGestureExample { 212 private uiContext: UIContext = new UIContext(); 213 private contentWidth: number = 0; 214 private contentHeight: number = 0; 215 private scaleMin: number = 0.3; 216 private scaleMax: number = 30.0; 217 private screenWidth: number = 0; 218 private screenHeight: number = 0; 219 @State pntX: number = 0; 220 @State pntY: number = 0; 221 @State curScale: number = 1; 222 @State preScale: number = 1; 223 @State offsetX: number = 0; 224 @State offsetY: number = 0; 225 @State matrix: matrix4.Matrix4Transit = matrix4.identity() 226 .translate({ x: this.offsetX, y: this.offsetY }) 227 .scale({ x: this.curScale, y: this.curScale }); 228 229 public updateMatrix(): void { 230 this.matrix = matrix4.identity() 231 .scale({ x: this.curScale, y: this.curScale }) 232 .translate({ x: this.uiContext.vp2px(this.offsetX), y: this.uiContext.vp2px(this.offsetY) }); 233 } 234 235 aboutToAppear(): void { 236 this.uiContext = this.getUIContext(); 237 let screenSize = display.getDefaultDisplaySync(); 238 this.screenWidth = this.uiContext.px2vp(screenSize.width); 239 this.screenHeight = this.uiContext.px2vp(screenSize.height); 240 } 241 242 build() { 243 Column() { 244 // Replace $r('app.media.img') with the image resource file you use. 245 Image($r('app.media.img')) 246 .objectFit(ImageFit.Contain) 247 .draggable(false) 248 .onComplete((event) => { 249 this.contentWidth = this.uiContext.px2vp(event!.contentWidth); 250 this.contentHeight = this.uiContext.px2vp(event!.contentHeight); 251 }) 252 .transform(this.matrix) 253 } 254 // The gesture event is triggered by a two-finger pinch. 255 .gesture( 256 PinchGesture({ fingers: 2 }) 257 .onActionStart((event: GestureEvent) => { 258 // Displayed size of the image before scaling 259 const displayWidth = this.contentWidth * this.curScale; 260 const displayHeight = this.contentHeight * this.curScale; 261 // Upper left corner coordinates before scaling 262 const left = (this.screenWidth - displayWidth) / 2 + this.offsetX; 263 const top = (this.screenHeight - displayHeight) / 2 + this.offsetY; 264 // Relative position (as a percentage) of the pinch center relative to the upper left corner of the displayed image 265 this.pntX = (event.pinchCenterX - left) / displayWidth; 266 this.pntY = (event.pinchCenterY - top) / displayHeight; 267 // Scale factor before the current operation 268 this.preScale = this.curScale; 269 }) 270 .onActionUpdate((event: GestureEvent) => { 271 // Target scale factor 272 this.curScale = this.preScale * event.scale; 273 let targetDisplayWidth = this.contentWidth * this.curScale; 274 let targetDisplayHeight = this.contentHeight * this.curScale; 275 // Coordinates of the pinch center after scaling 276 const pointX = (this.screenWidth - targetDisplayWidth) / 2 + targetDisplayWidth * this.pntX; 277 const pointY = (this.screenHeight - targetDisplayHeight) / 2 + targetDisplayHeight * this.pntY; 278 // Offset required to align the calculated point (pointX, pointY) with the actual pinch center after scaling 279 this.offsetX = event.pinchCenterX - pointX; 280 this.offsetY = event.pinchCenterY - pointY; 281 this.updateMatrix(); 282 }) 283 .onActionEnd((event: GestureEvent) => { 284 if (this.curScale < this.scaleMin || this.curScale > this.scaleMax) { 285 this.curScale = 1; 286 this.offsetX = 0; 287 this.offsetY = 0; 288 this.updateMatrix(); 289 } 290 }) 291 ) 292 } 293} 294``` 295 296  297