UIPinchGestureRecognizer和UIPanGestureRecognizer可以合并吗?

dug*_*gla 8 concatenation matrix-multiplication uigesturerecognizer ios

我正在努力想弄清楚是否有可能创建一个结合了UIPinchGestureRecognizer和UIPanGestureRecognizer的组合手势识别器.

我正在使用平移视图转换和捏视图缩放.我正在进行增量矩阵连接,以导出应用于视图的结果最终变换矩阵.该矩阵具有缩放和平移.使用单独的手势识别器会导致抖动运动/缩放.不是我想要的.因此,我想在一个手势内处理一次缩放和翻译.有人可以说明如何做到这一点吗?

Pau*_*olt 18

2014年6月14日:使用ARC更新了iOS 7+的示例代码.

UIGestureRecognizers可以一起工作,您只需要确保不要删除当前视图的变换矩阵.使用CGAffineTransformScale方法和将变换作为输入的相关方法,而不是从头开始创建(除非您自己维护当前的旋转,缩放或平移).

下载Xcode项目

注意:iOS 7中的UIView在应用了Pan/Pinch/Rotate手势时表现得很奇怪.iOS 8修复了它,但我的解决方法是在代码中添加所有视图,如此代码示例.

演示视频

演示UIPinchGesture视频

  1. 将它们添加到视图并符合UIGestureRecognizerDelegate协议

    @interface ViewController () <UIGestureRecognizerDelegate>
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        UIView *blueView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 150, 150)];
        blueView.backgroundColor = [UIColor blueColor];
        [self.view addSubview:blueView];
        [self addMovementGesturesToView:blueView];
    
        // UIImageView's and UILabel's don't have userInteractionEnabled by default!
        UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"BombDodge.png"]]; // Any image in Xcode project
        imageView.center = CGPointMake(100, 250);
        [imageView sizeToFit];
        [self.view addSubview:imageView];
        [self addMovementGesturesToView:imageView];
    
        // Note: Changing the font size would be crisper than zooming a font!
        UILabel *label = [[UILabel alloc] init];
        label.text = @"Hello Gestures!";
        label.font = [UIFont systemFontOfSize:30];
        label.textColor = [UIColor blackColor];
        [label sizeToFit];
        label.center = CGPointMake(100, 400);
        [self.view addSubview:label];
        [self addMovementGesturesToView:label];
    }
    
    - (void)addMovementGesturesToView:(UIView *)view {
        view.userInteractionEnabled = YES;  // Enable user interaction
    
        UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
        panGesture.delegate = self;
        [view addGestureRecognizer:panGesture];
    
        UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)];
        pinchGesture.delegate = self;
        [view addGestureRecognizer:pinchGesture];
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 实现手势方法

    - (void)handlePanGesture:(UIPanGestureRecognizer *)panGesture {
        CGPoint translation = [panGesture translationInView:panGesture.view.superview];
    
        if (UIGestureRecognizerStateBegan == panGesture.state ||UIGestureRecognizerStateChanged == panGesture.state) {
            panGesture.view.center = CGPointMake(panGesture.view.center.x + translation.x,
                                                 panGesture.view.center.y + translation.y);
            // Reset translation, so we can get translation delta's (i.e. change in translation)
            [panGesture setTranslation:CGPointZero inView:self.view];
        }
        // Don't need any logic for ended/failed/canceled states
    }
    
    - (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinchGesture {
    
        if (UIGestureRecognizerStateBegan == pinchGesture.state ||
            UIGestureRecognizerStateChanged == pinchGesture.state) {
    
            // Use the x or y scale, they should be the same for typical zooming (non-skewing)
            float currentScale = [[pinchGesture.view.layer valueForKeyPath:@"transform.scale.x"] floatValue];
    
            // Variables to adjust the max/min values of zoom
            float minScale = 1.0;
            float maxScale = 2.0;
            float zoomSpeed = .5;
    
            float deltaScale = pinchGesture.scale;
    
            // You need to translate the zoom to 0 (origin) so that you
            // can multiply a speed factor and then translate back to "zoomSpace" around 1
            deltaScale = ((deltaScale - 1) * zoomSpeed) + 1;
    
            // Limit to min/max size (i.e maxScale = 2, current scale = 2, 2/2 = 1.0)
            //  A deltaScale is ~0.99 for decreasing or ~1.01 for increasing
            //  A deltaScale of 1.0 will maintain the zoom size
            deltaScale = MIN(deltaScale, maxScale / currentScale);
            deltaScale = MAX(deltaScale, minScale / currentScale);
    
            CGAffineTransform zoomTransform = CGAffineTransformScale(pinchGesture.view.transform, deltaScale, deltaScale);
            pinchGesture.view.transform = zoomTransform;
    
            // Reset to 1 for scale delta's
            //  Note: not 0, or we won't see a size: 0 * width = 0
            pinchGesture.scale = 1;
        }
    }
    
    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
        return YES; // Works for most use cases of pinch + zoom + pan
    }
    
    Run Code Online (Sandbox Code Playgroud)

资源

  • 除非使用gestureRecognizer同时允许手势识别,否则这不起作用:shouldRecognizeSimultaneouslyWithGestureRecognizer:UIGestureRecognizerDelegate方法. (8认同)
  • 在handlePanGesture中:状态与UIGestureRecognizerStateChanged进行两次比较 (2认同)