在iOS中使用三个手指取消锁定自定义手势识别器
我想用三个手指制作一个自定义手势识别器。这类似于手势识别器 我所需要的只是一个如何识别它的想法。 我的手势需要识别三个方向的三个手指。例如: 我希望图像有意义我需要使它在任何三个相反方向上都灵活。提前谢谢。任何帮助都将不胜感激在iOS中使用三个手指取消锁定自定义手势识别器,ios,iphone,objective-c,ios7,uipinchgesturerecognizer,Ios,Iphone,Objective C,Ios7,Uipinchgesturerecognizer,我想用三个手指制作一个自定义手势识别器。这类似于手势识别器 我所需要的只是一个如何识别它的想法。 我的手势需要识别三个方向的三个手指。例如: 我希望图像有意义我需要使它在任何三个相反方向上都灵活。提前谢谢。任何帮助都将不胜感激 我知道子类方法,我已经用单手指创建了自定义手势,如半圆、全圆。我需要一个关于如何处理的编码想法。您需要创建自己的UIGestureRecognitor子类(我们称之为DRThreeFingerPinchGestureRecognitor),并在其中实现: – tou
我知道子类方法,我已经用单手指创建了自定义手势,如半圆、全圆。我需要一个关于如何处理的编码想法。您需要创建自己的
UIGestureRecognitor
子类(我们称之为DRThreeFingerPinchGestureRecognitor
),并在其中实现:
– touchesBegan:withEvent:
– touchesMoved:withEvent:
– touchesEnded:withEvent:
– touchesCancelled:withEvent:
这些方法在系统接受触摸时调用,可能在触摸发送到视图本身之前调用(取决于手势识别器的设置方式)。这些方法中的每一种都将为您提供一组触摸,您可以检查视图中的当前位置和以前的位置。由于按压手势相对来说非常简单,因此此信息足以让您测试用户是否正在进行按压,并使测试失败(uigesturecognizerstatefiled
)。如果状态未通过–touchesend:withEvent:
,则可以识别该手势
我说捏手势很简单,因为你可以很容易地跟踪每一次触摸,并观察它相对于其他触摸和自身的移动情况。如果某个角度的阈值通过并被打破,则测试失败,否则允许继续测试。如果触摸没有以单独的角度彼此移动,则测试失败。你必须考虑向量的角度是可以接受的,因为120度对于三个最常见的手指(拇指+食指+中指)不是最佳的。您可能只想检查向量是否没有碰撞
请务必阅读,以深入了解各种方法以及子类注释。我认为轨迹角度将您引入错误的路径。我认为如果你不根据手指之间的角度来限制它,那么这可能是一个更灵活、更直观的手势。如果你只是把它当作三个手指的捏法来处理,不管手指之间是如何相对移动的,那么它就不那么容易出错。这就是我要做的:
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
然后你可以用差分系数做任何你想做的事。如果大于1,则夹点已远离中心。如果它小于1,它就会向中心移动。这也将使用户能够保持两个手指静止,只移动第三个手指来执行手势。这将解决用户可能遇到的某些可访问性问题
此外,您可以始终跟踪触摸移动事件之间的增量变化,但它们的时间间隔不会相等,我怀疑您在处理这些事件时会遇到更多问题
我也为伪代码道歉。如果有什么不清楚的地方,我可以看一个真实的例子。给未来读者的快速提示:用三个手指解开/捏的方法是加上ab、bc、ac的距离 但是,如果您的图形包正好有“三角形区域”,只需使用它即可。(“它保存了一整行代码!”) 希望能有帮助
您只需跟踪: 三个手指之间的距离! 简单地将“每个”排列相加 (好的,有三个……ab,ac和cb。只要把它们加起来,就够了!) 比如说,当该值比起始值增加三倍时,即为“向外三英寸” 。。。令人惊讶的是,事情就这么简单 角度是无关紧要的
脚注如果你想成为一个聪明人:这适用于任何捏/拧手势,2、3个手指,无论什么: 跟踪总距离(我的意思是速度)的导数,而不是距离。(奇怪的是,这通常更容易做到!因为它是无状态的!您只需查看上一帧!!!!) 换句话说,当手指的伸展/收缩速度达到某个值,而不是起始值的倍数时,就会触发手势
更有趣的脚注强> 然而这里有一个微妙的问题:每当你做这样的事情(任何平台),你都必须小心地在玻璃上测量 如果你只是在做距离(即,我上面的第一个解决方案),当然所有的东西都会抵消,你可以说“如果它加倍”(以像素为单位——点——管它呢)。但是,如果你以任何姿势计算速度,那么有点奇怪,你必须在现实世界中以米/秒为单位找到速度,这听起来很奇怪!当然,你不能完全做到这一点(尤其是在android上),因为玻璃的大小有些不同,但你必须接近它。这里有一篇很长的文章讨论这个问题,在实践中,你通常不得不将就“每秒屏幕宽度”,这很好。(但这在手机、大型平板电脑和如今的“表面”型产品上可能有很大的不同。在整个iMac屏幕上,0.1屏幕宽度每秒可能很快,但在iPhone上,这并不是一种手势,什么都不是。)
最后的脚注!我只是不知道苹果是否在手势识别中使用了“距离倍数”或“玻璃速度”,或者可能是某种微妙的混合。我从来没有读过他们写的评论文章
另一个脚注如果出于任何原因,您确实想找到三角形的“中心”(我指的是三个手指的中心)。这是一个久经考验的问题
#import <UIKit/UIKit.h>
#import <UIKit/UIGestureRecognizerSubclass.h>
@interface UnPinchGestureRecognizer : UIGestureRecognizer
@property CGFloat averageDistanceFromCenter;
@end
#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;
}
}