旋钮旋转手势识别器

时间:2013-10-29 15:43:12

标签: ios objective-c rotation uigesturerecognizer

我正在尝试创建一个能够检测4个手指旋转的手势识别器(类似于旋转音量旋钮时)。
主要思想是创建UIRotateGestureRecognizer的子类并覆盖其方法。在-touchesBegan我检测到触摸次数,如果该次数低于4,则手势状态失败。
之后我将位置点传递给找到凸包直径的算法。如果你考虑一下,你的手指就是顶点,我只需要找到最大距离的两个顶点。获得这两点我将它们称为ivar并将它传递给超类,因为它只用两根手指进行简单旋转。
它不起作用:

  1. 触摸的检测似乎很难
  2. 很少-touchesHasMoved被称为
  3. 当它被称为挂起大部分时间时
  4. 有人可以帮助我吗?

    以下是代码:

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
        if (touches.count<4) {
            //FAIL
            self.state = UIGestureRecognizerStateFailed;
            return;
        }
    
        //Find the diameter of the convex hull
        NSArray * touchesArray = [touches allObjects];
        NSMutableArray * pointsArray = @[].mutableCopy;
        for (UITouch * touch in touchesArray) {
            [pointsArray addObject:[NSValue valueWithCGPoint:[touch locationInView:touch.view]]];
        }
        DiameterType convexHullDiameter = getDiameterFromPoints(pointsArray);
        CGPoint firstPoint =  convexHullDiameter.firstPoint;
        CGPoint secondPoint = convexHullDiameter.secondPoint;
        for (UITouch * touch in touchesArray) {
            if (CGPointEqualToPoint([touch locationInView:touch.view], firstPoint) ) {
                self.fistTouch = touch;
            }
            else if (CGPointEqualToPoint([touch locationInView:touch.view], secondPoint)){
                self.secondTouch = touch;
            }
        }
        //Calculating the rotation center as a mid point between the diameter vertices
        CGPoint rotationCenter = (CGPoint) {
            .x = (convexHullDiameter.firstPoint.x + convexHullDiameter.secondPoint.x)/2,
            .y = (convexHullDiameter.firstPoint.y + convexHullDiameter.secondPoint.y)/2
        };
        self.rotationCenter = rotationCenter;
        //Passing touches to super as a fake rotation gesture
        NSSet * touchesSet = [[NSSet alloc] initWithObjects:self.fistTouch, self.secondTouch, nil];
        [super touchesBegan:touchesSet withEvent:event];
    }
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
        if (touches.count<4) {
            self.state = UIGestureRecognizerStateFailed;
            return;
        }
    
        [super touchesMoved:[[NSSet alloc] initWithObjects:self.fistTouch, self.secondTouch, nil] withEvent:event];
    }
    
    - (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event  {
        [super touchesCancelled:[[NSSet alloc] initWithObjects:self.fistTouch, self.secondTouch, nil] withEvent:event];
    }
    
    - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event  {
        [super touchesEnded:[[NSSet alloc] initWithObjects:self.fistTouch, self.secondTouch, nil] withEvent:event];
    }
    

3 个答案:

答案 0 :(得分:2)

初始检测困难的原因是所有触摸可能不会同时开始。 touchesBegan可能会被多次调用,因为屏幕上会出现单独的触摸。您可以使用event参数通过event.allTouches查询所有当前触摸。因此,您当前触发手势失败的方法将无效。如果touches.count是&lt ;,则不应将状态设置为失败。 4而是只返回if.allTouches.count&lt; 4.如果第四次触摸在第一次触摸后的某个时间内没有发生,您可以使用计时器将状态设置为失败。

touchesMoved可能存在问题,因为事件对象中的触摸与您传递给super的集合中的触摸不匹配。

答案 1 :(得分:1)

  

如果你考虑一下,你的手指就是顶点,我只需要找到最大距离的两个顶点。

即使你能够欺骗UIGestureRecognizer,我也不认为这会在实践中发挥作用。

这就是我以“正确”的方式实现算法的方法:

  1. 记住'旧'的触动。
  2. 当您获得“新”触摸时,请尝试将每个手指与之前的触摸相匹配。如果你不能,那就失败。
  3. 计算'新'+'旧'触摸的中心。
  4. 对于两步前确定的4个手指中的每一个,计算角度以弧度为单位,近似为

    new(i) - old(i) divided by distance to center

  5. 如果任何角度太大(> 0.5),则失败。

  6. 这可以保证近似值有效。
  7. 现在计算4个角度的平均值。
  8. 恭喜,您现在拥有旋转角度(以弧度为单位)。

答案 2 :(得分:0)

如果我有足够的代表,我会把它放在评论中。

[super touchesMoved:[[NSSet alloc] initWithObjects:self.fistTouch, self.secondTouch, nil] withEvent:event];

您正在使用名为fistTouch的内容,这听起来并不像您想要的那样。我的猜测是你想要firstTouch

此外,正在进行的手势之间可能存在可能相互重叠的冲突。您是否知道iOS7中有一个4指缩小图像是系统范围的手势?此外,应用程序中的4指放大将关闭它。