UITapGestureRecognizerとUIButton共用でかつダブルタップ対応の時


UITapGestureRecognizer でタップを検知するとき、シングルタップとダブルタップの両方に対応するために2つ登録する。

UITapGestureRecognizer* g1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
g1.numberOfTapsRequired = 1;
g1.numberOfTouchesRequired = 1;
g1.delegate = self;
[self.view addGestureRecognizer:g1];

UITapGestureRecognizer* g2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
g2.numberOfTapsRequired = 2;
g2.numberOfTouchesRequired = 1;
[self.view addGestureRecognizer:g2];

でもこれだけだと、ダブルタップしたときにもhandleSingleTapを呼んでしまう。
そこで下記を書き足す。

[g1 requireGestureRecognizerToFail:g2];

これでダブルタップのときにhandleSingleTapは呼ばれなくなる。

さて、ここで、UIButton をこのViewに追加したくなるとする。しかし、UITapGestureRecognizerがあるせいで、UIButtonは反応しなくなってしまっている。
でこれを回避するためということで、以下を追加する。

g1.cancelsTouchesInView = NO;
g2.cancelsTouchesInView = NO;

ところが、これがうまく行かない。UIButtonはシングルタップを認識しない。しかし、UIButtonをダブルタップしてみると通る。
試しに、[g1 requireGestureRecognizerToFail:g2];を外してみたら正常にシングルタップでUIButtonが反応した。
理由はよくわからないがそうなっている。
でも、[g1 requireGestureRecognizerToFail:g2];を外すわけにはいかない。どうする?

ググってみて見つけた方法

UIButton inside a view that has a UITapGestureRecognizer
に書かれている。

– (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIButton class]]){
return FALSE;
}
return TRUE;
}

というのがそのまま使えた。
ヘッダに UIGestureRecognizerDelegate を追加して、 g1.delegete = self; すること。