在iOS中使用三个手指取消固定自定义手势识别器

时间:2014-05-11 10:07:56

标签: ios iphone objective-c ios7 uipinchgesturerecognizer

我想用三个手指制作自定义手势识别器。这与unpinch手势识别器类似。

我只需要了解如何识别它。

我的手势需要识别三个方向的三个手指。例如:

enter image description here

enter image description here

enter image description here

我希望图像有意义。 我需要在任何三个相反的方向上灵活处理。提前致谢。任何帮助将不胜感激。

我知道子类方法,我已经用单指半圆形,全圆形创建了自定义手势。我需要一个关于如何处理它的编码想法。

4 个答案:

答案 0 :(得分:4)

您需要创建自己的UIGestureRecognizer子类(让我们称之为DRThreeFingerPinchGestureRecognizer)并在其中实现:

– touchesBegan:withEvent:
– touchesMoved:withEvent:
– touchesEnded:withEvent:
– touchesCancelled:withEvent:

当系统接受触摸并且可能在将它们发送到视图本身之前调用这些方法(取决于您设置手势识别器的方式)。这些方法中的每一种都会为您提供一组触摸,您可以在其中查看视图中的当前位置和之前的位置。由于捏合手势相对非常简单,因此该信息足以让您测试用户是否正在执行捏合,并且测试失败(UIGestureRecognizerStateFailed)。如果状态未被– touchesEnded:withEvent:失败,您可以识别该手势。

我说捏手势很简单,因为你可以轻松跟踪每一次触摸,看看它与其他触摸相比如何移动。如果角度的阈值被传递和破坏,则测试失败,否则您允许它继续。如果触摸不以彼此不同的角度移动,则表示测试失败。您必须使用矢量的可接受角度,因为对于三个最常见的手指(拇指+指数+中指),120度不是最佳的。您可能只想检查矢量是否没有碰撞。

请务必阅读UIGestureRecognizer documentation,深入了解各种方法,以及子类记录。

答案 1 :(得分:3)

我认为跟踪角度正在引导你走错路。我认为如果你不根据手指之间的角度约束它,它可能是一个更灵活和直观的手势。无论手指如何相对移动,只要将其作为三指夹点处理,它就不会出错。这就是我要做的事情:

if(presses != 3) {
     state = UIGestureRecognizerStateCancelled;
     return;
}

// After three fingers are detected, begin tracking the gesture.
state =  UIGestureRecognizerStateBegan; 
central_point_x = (point1.x + point2.x + point3.x) / 3;
central_point_y = (point1.y + point2.y + point3.y) / 3;

// Record the central point and the average finger distance from it.
central_point = make_point(central_point_x, central_point_y);
initial_pinch_amount = (distance_between(point1, central_point) + distance_between(point2, central_point) + distance_between(point3, central_point)) / 3;

然后,每次更新触摸的动作:

if(presses != 3) {
     state = UIGestureRecognizerStateEnded;
     return;
}

// Get the new central point
central_point_x = (point1.x + point2.x + point3.x) / 3;
central_point_y = (point1.y + point2.y + point3.y) / 3;
central_point = make_point(central_point_x, central_point_y);

// Find the new average distance
pinch_amount = (distance_between(point1, central_point) + distance_between(point2, central_point) + distance_between(point3, central_point)) / 3;

// Determine the multiplicative factor between them.
difference_factor = pinch_amount / initial_pinch_amount

然后你可以用difference_factor做任何你想做的事。如果它大于1,则夹点已从中心移开。如果它小于1,它就会向中心移动。这也将使用户能够握住两个手指静止,只移动三分之一来执行手势。这将解决用户可能遇到的某些辅助功能问题。

此外,您可以随时跟踪触摸移动事件之间的增量变化,但它们的时间间隔不会相等,我怀疑您处理它时会遇到更多麻烦。

我也为伪代码道歉。如果事情不明确,我可以看看做一个真实的例子。

答案 2 :(得分:3)

未来读者的快速说明:用三根手指进行松开/捏合的方式是增加距离ab,bc,ac。

但是,如果您的图形包恰好有三角形的"区域" - 只需使用它。 ("它保存了一整行代码!")

希望它有所帮助。


您需要做的就是追踪:

三根手指之间的距离!

简单地加上"每一个"置换

(好吧,那里有三个...... ab,ac和cb。只需加上那些;那就是它的全部!)

当该值(比如说,从起始值增加三倍)时,该值为"向外三重旋转"。

......令人惊讶的是它很简单。

角度无关紧要。


脚注如果你想成为智能手机:这适用于任何捏/卸指手势,2,3指,无论如何:

跟踪和距离的导数(我的意思是说,速度)而不是距离。 (奇怪的是,这通常很容易!因为它是无国籍的!你只需看看前一帧!!!!)

换句话说,当手指的伸展/收缩VELOCITY达到某个值而不是起始值的倍数时,手势就会触发。


更有趣的脚注!

然而这里有一个微妙的问题:每当你做这样的事情(任何平台)时,你必须小心测量玻璃上的"

如果你正在做距离(即我上面的第一个解决方案),当然一切都取消了,你可以说"如果它加倍" (以像素为单位 - 分数 - 无论如何)。但是如果你在任何手势中做速度作为计算的一部分,那么有点令人惊讶的是,你必须在现实世界中逐字地找到以米/秒为单位的速度,这听起来很奇怪!当然你不能完全这样做(特别是对于android)coz玻璃尺寸有所不同,但你必须接近它。这是一个讨论这个问题的长篇文章http://answers.unity3d.com/questions/292333/how-to-calculate-swipe-speed-on-ios.html在实践中,你通常需要使用"每秒屏幕宽度"这很不错。 (但这可能会在手机,大型平板电脑和现在的表面上大不相同......在整个iMac屏幕上,0.1屏幕宽度可能会很快,但在iPhone上什么都不是,而不是手势。)


最后的脚注!我根本不知道Apple是否使用"距离倍数"或者"玻璃速度"在他们的手势识别中,或者也可能是一些微妙的混合。我从未读过他们评论过的文章。


另一个脚注! - 如果出于某种原因你想找到" center"三角形(我的意思是三个手指的中心)。对于游戏程序员来说,这是一个经常出现的问题,因为毕竟所有3D网格都是三角形。

幸运的是,找到三个点的中心是微不足道的,只需添加三个向量并除以三! (令人困惑的是,它甚至可以在更高的尺寸上工作!!)

你可以在这个问题上看到无穷无尽的帖子......

http://answers.unity3d.com/questions/445442/calculate-uv-at-center-of-triangle.html

http://answers.unity3d.com/questions/424950/mid-point-of-a-triangle.html

可以想象,如果你是非常肛门,你会想要"重心"这更像是质量中心,只要google就可以了。

答案 3 :(得分:1)

UIGestureRecognizer的简单子类。它计算3个点的相对三角形中心,然后计算距该中心的平均距离,角度不重要。然后,检查手势处理程序中的平均距离。

·H

#import <UIKit/UIKit.h>
#import <UIKit/UIGestureRecognizerSubclass.h>
@interface UnPinchGestureRecognizer : UIGestureRecognizer
 @property CGFloat averageDistanceFromCenter;
@end

的.m

#import "UnPinchGestureRecognizer.h"
@implementation UnPinchGestureRecognizer

-(CGPoint)centerOf:(CGPoint)pnt1 pnt2:(CGPoint)pnt2 pnt3:(CGPoint)pnt3
{
    CGPoint center;
    center.x = (pnt1.x + pnt2.x + pnt3.x) / 3;
    center.y = (pnt1.y + pnt2.y + pnt3.y) / 3;
    return center;
}
-(CGFloat)averageDistanceFromCenter:(CGPoint)center pnt1:(CGPoint)pnt1 pnt2:(CGPoint)pnt2 pnt3:(CGPoint)pnt3
{
    CGFloat distance;
    distance = (sqrt(fabs(pnt1.x-center.x)*fabs(pnt1.x-center.x)+fabs(pnt1.y-center.y)*fabs(pnt1.y-center.y))+
                sqrt(fabs(pnt2.x-center.x)*fabs(pnt2.x-center.x)+fabs(pnt2.y-center.y)*fabs(pnt2.y-center.y))+
                sqrt(fabs(pnt3.x-center.x)*fabs(pnt3.x-center.x)+fabs(pnt3.y-center.y)*fabs(pnt3.y-center.y)))/3;
    return distance;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    if ([touches count] == 3) {
        [super touchesBegan:touches withEvent:event];
        NSArray *touchObjects = [touches allObjects];
        CGPoint pnt1 = [[touchObjects objectAtIndex:0] locationInView:self.view];
        CGPoint pnt2 = [[touchObjects objectAtIndex:1] locationInView:self.view];
        CGPoint pnt3 = [[touchObjects objectAtIndex:2] locationInView:self.view];

        CGPoint center = [self centerOf:pnt1 pnt2:pnt2 pnt3:pnt3];
        self.averageDistanceFromCenter = [self averageDistanceFromCenter:center pnt1:pnt1 pnt2:pnt2 pnt3:pnt3];
        self.state = UIGestureRecognizerStateBegan;
    }
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    if ([touches count] == 3)
    {
        NSArray *touchObjects = [touches allObjects];
        CGPoint pnt1 = [[touchObjects objectAtIndex:0] locationInView:self.view];
        CGPoint pnt2 = [[touchObjects objectAtIndex:1] locationInView:self.view];
        CGPoint pnt3 = [[touchObjects objectAtIndex:2] locationInView:self.view];

        CGPoint center = [self centerOf:pnt1 pnt2:pnt2 pnt3:pnt3];
        self.averageDistanceFromCenter = [self averageDistanceFromCenter:center pnt1:pnt1 pnt2:pnt2 pnt3:pnt3];
        self.state = UIGestureRecognizerStateChanged;
        return;
    }

}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    self.state = UIGestureRecognizerStateEnded;
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    self.state = UIGestureRecognizerStateFailed;
}

@end

执行手势,我有一个最大平均距离设置开始,然后最小结束,你也可以在更改期间检查:

-(IBAction)handleUnPinch:(UnPinchGestureRecognizer *)sender
{
    switch (sender.state) {
        case UIGestureRecognizerStateBegan:
            //If you want a maximum starting distance
            self.validPinch = (sender.averageDistanceFromCenter<75);
            break;
        case UIGestureRecognizerStateEnded:
            //Minimum distance from relative center
            if (self.validPinch && sender.averageDistanceFromCenter >=150) {
                NSLog(@"successful unpinch");
            }
            break;
        default:
            break;
    }
}