使用PinchGesture; 如何放大用户的手指实际"捏"的位置?

Bri*_*any 11 objective-c ios uipinchgesturerecognizer

我已经在我的应用程序中的UIImageView上实现了UIPinchGestureRecognizer,但是无论我在哪里捏图像,它似乎都放大到相同的位置.有谁知道如何让它放大到用户实际"捏"的位置?见下面的代码.

ViewController.m

 - (IBAction)scaleImage:(UIPinchGestureRecognizer *)recognizer {

   recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);
   recognizer.scale = 1; 

 }

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
{
    BOOL shouldReceiveTouch = YES;

    if (gestureRecognizer == tap) {
        shouldReceiveTouch = (touch.view == featureImage);
    }
    return shouldReceiveTouch;
}
Run Code Online (Sandbox Code Playgroud)

rob*_*off 35

缩放变换使原点(0,0)保持不变.因此,要围绕特定点缩放视图,必须首先将该点转换为原点,然后应用缩放,然后转换回来.

- (IBAction)pinchGestureDidFire:(UIPinchGestureRecognizer *)pinch {
Run Code Online (Sandbox Code Playgroud)

首先,我们得到的观点受到挤压.

    UIView *pinchView = pinch.view;
Run Code Online (Sandbox Code Playgroud)

要计算夹点的中心,我们需要视图边界的中点,所以我们也得到了界限:

    CGRect bounds = pinchView.bounds;
Run Code Online (Sandbox Code Playgroud)

该中心基于捏的触摸的质心,我们得到这样的方式:

    CGPoint pinchCenter = [pinch locationInView:pinchView];
Run Code Online (Sandbox Code Playgroud)

但实际上我们需要相对于视图中心的夹点偏移,因为默认情况下视图的变换相对于视图的中心.(您可以通过更改视图来更改此设置layer.anchorPoint.)

    pinchCenter.x -= CGRectGetMidX(bounds);
    pinchCenter.y -= CGRectGetMidY(bounds);
Run Code Online (Sandbox Code Playgroud)

现在我们可以更新视图的转换.首先,我们获得当前的变换:

    CGAffineTransform transform = pinchView.transform;
Run Code Online (Sandbox Code Playgroud)

然后我们更新它以将夹点中心转换为原点:

    transform = CGAffineTransformTranslate(transform, pinchCenter.x, pinchCenter.y);
Run Code Online (Sandbox Code Playgroud)

现在我们可以应用比例:

    CGFloat scale = pinch.scale;
    transform = CGAffineTransformScale(transform, scale, scale);
Run Code Online (Sandbox Code Playgroud)

然后我们将视图翻译回来:

    transform = CGAffineTransformTranslate(transform, -pinchCenter.x, -pinchCenter.y);
Run Code Online (Sandbox Code Playgroud)

现在我们可以使用修改后的转换更新视图:

    pinchView.transform = transform;
Run Code Online (Sandbox Code Playgroud)

最后,我们重置了手势识别器的比例,因为我们已应用当前比例:

    pinch.scale = 1.0;
}
Run Code Online (Sandbox Code Playgroud)

演示:

捏缩放

请注意,在模拟器中,您可以按住选项(alt)进行捏合手势.按住shift(同时保持选项)将两个触摸移动到一起.

这是复制/粘贴的所有代码:

- (IBAction)pinchGestureDidFire:(UIPinchGestureRecognizer *)pinch {
    UIView *pinchView = pinch.view;
    CGRect bounds = pinchView.bounds;
    CGPoint pinchCenter = [pinch locationInView:pinchView];
    pinchCenter.x -= CGRectGetMidX(bounds);
    pinchCenter.y -= CGRectGetMidY(bounds);
    CGAffineTransform transform = pinchView.transform;
    transform = CGAffineTransformTranslate(transform, pinchCenter.x, pinchCenter.y);
    CGFloat scale = pinch.scale;
    transform = CGAffineTransformScale(transform, scale, scale);
    transform = CGAffineTransformTranslate(transform, -pinchCenter.x, -pinchCenter.y);
    pinchView.transform = transform;
    pinch.scale = 1.0;
}
Run Code Online (Sandbox Code Playgroud)


Bru*_*ino 13

迅速实施抢劫答案:

@objc private func pinchHandler(gesture: UIPinchGestureRecognizer) {
    if let view = gesture.view {

        switch gesture.state {
        case .changed:
            let pinchCenter = CGPoint(x: gesture.location(in: view).x - view.bounds.midX,
                                      y: gesture.location(in: view).y - view.bounds.midY)
            let transform = view.transform.translatedBy(x: pinchCenter.x, y: pinchCenter.y)
                                            .scaledBy(x: gesture.scale, y: gesture.scale)
                                            .translatedBy(x: -pinchCenter.x, y: -pinchCenter.y)
            view.transform = transform
            gesture.scale = 1
        case .ended:
            // Nice animation to scale down when releasing the pinch.
            // OPTIONAL
            UIView.animate(withDuration: 0.2, animations: {
                view.transform = CGAffineTransform.identity
            })
        default:
            return
        }


    }
}
Run Code Online (Sandbox Code Playgroud)