【问题标题】:Knob rotation gesture recognizer旋钮旋转手势识别器
【发布时间】:2013-10-29 15:43:11
【问题描述】:

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

  1. 触摸检测似乎很难
  2. -touchesHasMoved 很少被调用
  3. 当它被调用时,它大部分时间都挂起

有人可以帮我吗?

代码如下:

- (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];
}

【问题讨论】:

  • 你不能只使用 2 根手指并使用旋转/俯仰手势(默认来自 ios)吗?我这么说是因为我用两个手指来改变音响系统的音量,而不是 4 个。可能我会用更多的手指来处理重物,比如硬自来水,p.ex.
  • 如果我只用两根手指,从用户的角度来看就不一样了。
  • 也许使用“[[event allTouches] anyObject];”而不是“[touches allObjects];”有点帮助,我不明白你的问题到底是什么。

标签: ios objective-c rotation uigesturerecognizer


【解决方案1】:

初始检测很难的原因是所有触摸可能不会同时开始。 touchesBegan 可能会被多次调用,因为单独的触摸落在屏幕上。您可以通过 event.allTouches 使用 event 参数来查询所有当前的触摸。因此,您当前触发手势失败的方法将不起作用。如果 touches.count

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

【讨论】:

  • 谢谢,你所有的 cmets 和建议都很有意义
【解决方案2】:

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

我认为这在实践中是行不通的,即使你能够欺骗UIGestureRecognizer

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

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

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

  5. 如果任何角度过大 (&gt; 0.5),则失败。

  6. 这保证了近似值是有效的。
  7. 现在计算 4 个角度的平均值。

恭喜,您现在有了旋转角度(以弧度为单位)。

【讨论】:

  • 我不明白.. 中心仅在圆形或对称对象中得到很好的定义。视图上的 4 次触摸只能近似为中心。要做到这一点,您需要找到直径并将中心定义为中点。第 3 步是什么意思?
  • 您总是可以通过取其对象坐标的平均值来找到物理系统的质心,在这种情况下,(new(1) + new(2) +... + old(4)) / 8(对 x 和 y 坐标都这样做)。这个中心可能和之前的事件不一样,但你仍然可以用它来找到旋转角度。
  • 感谢 ilya,我得到了...一元质量的中心...我会试一试的。
【解决方案3】:

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

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

您正在使用名为fistTouch 的东西,这听起来不像您想要的。我猜你想要firstTouch

此外,正在进行的手势之间可能会发生冲突,这些冲突可能会相互覆盖。你知道 iOS7 中有一个 4 指缩小是系统范围的手势吗?此外,在应用期间用 4 指放大也会将其关闭。

【讨论】:

  • 嗨 DrDisc,我的应该是这样的把戏:好的,你需要 4 个手指,但不是写下识别旋转的逻辑,我们为什么不把它伪装成 2手指旋转?此类是 RotationGesture 的子类,仅用 2 个手指制作。您对冲突手势的观察是正确的,但只有 iPad 有 4 个手指“应用程序退出”,您可以禁用它。还是谢谢
猜你喜欢
  • 2012-08-15
  • 2018-01-19
  • 1970-01-01
  • 1970-01-01
  • 2018-02-01
  • 2012-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多