我知道使用Apple API过滤oneTap / doubleTap。代码如下。
UITapGestureRecognizer *doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(handleDoubleTap:)];
doubleTapGestureRecognizer.numberOfTapsRequired = 2;
[self addGestureRecognizer:doubleTapGestureRecognizer];
UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
singleTapGestureRecognizer.numberOfTapsRequired = 1;
**[singleTapGestureRecognizer requireGestureRecognizerToFail: doubleTapGestureRecognizer];**
[self addGestureRecognizer:singleTapGestureRecognizer];
但是oneTap / doubleTap checkDelayTime感觉太长了(约0.5秒?)。 一般来说App的用户反应非常快。虽然0.5秒通常是短时间。但在移动设备环境中是长期的,因为用户的反应非常重要。
说到这一点,YouTubeApp 有一个非常完美的算法,关于过滤oneTap / doubleTap的时刻。 oneTap-doubleTap checkDelay是VeryVeryShort完美优化。
oneTap(show / hidden controlBar)
doubleTap(完整/默认videoScreenSize)
如何实施YoutubeApp?关于oneTap-doubleTap过滤不使用requireGestureRecognizerToFail选择器。关于非常短的延迟oneTap-doubleTap区分。
我认为YoutubeApp不使用requireGestureRecognizer选择器。
答案 0 :(得分:21)
执行此操作的最简单方法是继承 UITapGestureRecognizer ,而不是一般的UIGestureRecognizer。
像这样:
#import <UIKit/UIGestureRecognizerSubclass.h>
#define UISHORT_TAP_MAX_DELAY 0.2
@interface UIShortTapGestureRecognizer : UITapGestureRecognizer
@end
简单地实施:
@implementation UIShortTapGestureRecognizer
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(UISHORT_TAP_MAX_DELAY * NSEC_PER_SEC)), dispatch_get_main_queue(), ^
{
// Enough time has passed and the gesture was not recognized -> It has failed.
if (self.state != UIGestureRecognizerStateRecognized)
{
self.state = UIGestureRecognizerStateFailed;
}
});
}
@end
答案 1 :(得分:15)
没有手势识别器,这是最容易的。然后你可以控制延迟。下面的代码是Apple在我的一个项目中使用的原始文档的变体。我有blog post that talks about it as well。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if (touch.tapCount == 2) {
//This will cancel the singleTap action
[NSObject cancelPreviousPerformRequestsWithTarget:self];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if (touch.tapCount == 1) {
//if they tapped within the coin then place the single tap action to fire after a delay of 0.3
if (CGRectContainsPoint(coin.frame,[touch locationInView:self.view])){
//this is the single tap action being set on a delay
[self performSelector:@selector(onFlip) withObject:nil afterDelay:0.3];
}else{
//I change the background image here
}
} else if (touch.tapCount == 2) {
//this is the double tap action
[theCoin changeCoin:coin];
}
}
答案 2 :(得分:13)
您需要做的只是添加额外的代码行以使用requireGestureRecognizerToFail
[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];
然后整个代码变为:
UITapGestureRecognizer *doubleTapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(beginComicTransitions:)] autorelease];
doubleTapRecognizer.numberOfTapsRequired = 2;
doubleTapRecognizer.numberOfTouchesRequired = 1;
doubleTapRecognizer.delegate = self;
UITapGestureRecognizer *singleTapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(bringMenu:)] autorelease];
singleTapRecognizer.numberOfTapsRequired = 1;
singleTapRecognizer.numberOfTouchesRequired = 1;
singleTapRecognizer.delegate = self;
[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];
这里的requireGestureRecognizerToFail
表示:
swift版本代码是:
let doubleTap = UITapGestureRecognizer(target: self, action: "doubleTapped:")
doubleTap.numberOfTapsRequired = 2
doubleTap.numberOfTouchesRequired = 1
self.scrollView.addGestureRecognizer(doubleTap)
let singleTap = UITapGestureRecognizer(target: self, action: "singleTap:")
singleTap.numberOfTapsRequired = 1
singleTap.numberOfTouchesRequired = 1
self.scrollView.addGestureRecognizer(singleTap)
singleTap.requireGestureRecognizerToFail(doubleTap)
答案 3 :(得分:1)
这是一个用于双击的简单自定义手势识别器,您可以在其中指定点击之间允许的最长时间。这是基于@Walters的答案。
PbDoubleTapGestureRecognizer.h:
@interface PbDoubleTapGestureRecognizer : UIGestureRecognizer
@property (nonatomic) NSTimeInterval maximumDoubleTapDuration;
@end
PbDoubleTapGestureRecognizer.m:
#import "PbDoubleTapGestureRecognizer.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
@interface PbDoubleTapGestureRecognizer ()
@property (nonatomic) int tapCount;
@property (nonatomic) NSTimeInterval startTimestamp;
@end
@implementation PbDoubleTapGestureRecognizer
- (id)initWithTarget:(id)target action:(SEL)action {
self = [super initWithTarget:target action:action];
if (self) {
_maximumDoubleTapDuration = 0.3f; // assign default value
}
return self;
}
-(void)dealloc {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
}
- (void)reset {
[super reset];
[NSObject cancelPreviousPerformRequestsWithTarget:self];
self.tapCount = 0;
self.startTimestamp = 0.f;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
if (touches.count != 1 ) {
self.state = UIGestureRecognizerStateFailed;
} else {
if (self.tapCount == 0) {
self.startTimestamp = event.timestamp;
[self performSelector:@selector(timeoutMethod) withObject:self afterDelay:self.maximumDoubleTapDuration];
}
self.tapCount++;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
if (self.tapCount > 2) {
self.state = UIGestureRecognizerStateFailed;
} else if (self.tapCount == 2 && event.timestamp < self.startTimestamp + self.maximumDoubleTapDuration) {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
NSLog(@"Recognized in %f", event.timestamp - self.startTimestamp);
self.state = UIGestureRecognizerStateRecognized;
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesCancelled:touches withEvent:event];
self.state = UIGestureRecognizerStateFailed;
}
- (void)timeoutMethod {
self.state = UIGestureRecognizerStateFailed;
}
@end
你可以像这样使用它:
PbDoubleTapGestureRecognizer *doubleTapGr = [[PbDoubleTapGestureRecognizer alloc]initWithTarget:self action:@selector(_doubleTapAction)];
doubleTapGr.maximumDoubleTapDuration = 0.4;
[yourView addGestureRecognizer:doubleTapGr];
您可以将其与requireGestureRecognizerToFail:
结合使用,以获取所要求的行为。
答案 4 :(得分:0)
eladleb's答案的Swift 3.1 版本。
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesBegan(touches, with: event)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
if self?.state != .recognized {
self?.state = .failed
}
}
}
答案 5 :(得分:0)
如果您已经在按钮或视图上附加了动作,那么这是一个更简单的答案。首先,更改IBAction,使其包含UIEvent(不要忘记将其重新连接到您的按钮或在Storyboard中查看):
-(IBAction)buttonAction:(id)sender forEvent:(UIEvent*)event
下一步,您可以在您的事件中捕获事件的触摸,然后轻松测试点击次数:
-(IBAction)buttonAction:(id)sender forEvent:(UIEvent*)event {
UITouch* firstTouch = nil;
if ((nil != ((firstTouch = event.allTouches.allObjects.firstObject)))
&& (2 == firstTouch.tapCount))
{
// do something for double-tap
} else {
// do something for single-tap
}
}
您可以针对其他事件参数(例如长按)使用其他情况扩展此解决方案。
答案 6 :(得分:-1)
@interface NaMeClass ()
@property (nonatomic, strong) UITapGestureRecognizer * singleTap;
@property (nonatomic, strong) NSTimer *timer;
@end
// ... ...代码
//viewDidLoad
self.singleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapIcon:)];
self.singleTap.numberOfTapsRequired = 1;
self.singleTap.cancelsTouchesInView = YES;
self.singleTap.delaysTouchesBegan = YES;
[self addGestureRecognizer:self.singleTap];
//.....code
-(void)tapIcon:(UITapGestureRecognizer *)tapGesture
{
if (tapGesture.state == UIGestureRecognizerStateEnded){
if (!self.timer) {
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.2
target:self selector:@selector(singleTap) userInfo:nil repeats:NO];
}else{
[self doubleTap];
}
}
}
-(void)singleTap{
[self.timer invalidate];
self.timer = nil;
NSLog(@"1111111111111");
}
-(void)doubleTap{
[self.timer invalidate];
self.timer = nil;
NSLog(@"22222222222");
}