以前、UINavigationBarのleftBarButtonItem の当たり判定が見た目よりも広かった件なんてのを書いていました。
この現象をもっとちゃんと調べて書いてあるブログ記事があります。iPhone の当たり判定を検証した
UINavigationBarに乗せるBarButtonItemは、当たり判定がはみ出しています。シンプルなUIだと良いのですが、NavigationBarの真下に何か配置すると、下の方を押したつもりでBarButtonItemが反応する事があって、「押しにくい」と言われる事があります。
下にはみ出している当たり判定は、UINavigationBarのhitTest:を上書きして回避出来る
UINavigationBarのleftBarButtonItem の当たり判定が見た目よりも広かった件だと、UINavigationBarにaddSubviewして制御しようとしてます。他の方法で当たり判定を制御する実装がStack Overflowに紹介されていました。Why does UINavigationBar steal touch events? - Stack Overflow この実装はUINavigationBarのhitTestを上書きしています。
@interface HitTestNavigationBar : UINavigationBar
@end
@implementation HitTestNavigationBar
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
NSLog( @"hitTest point.y=%.1f",point.y);
if ([self pointInside:point withEvent:event]) {
self.userInteractionEnabled = YES;
} else {
self.userInteractionEnabled = NO;
}
UIView *view = [super hitTest:point withEvent:event];
return view;
}
@end
このコード、self.userInteractionEnableを変えてるだけ、なのだけど、これで上手く動作します。
ではなぜ、userInterfaceEnableを変えるだけで当たり判定が変わるのでしょうか?
UINavigationBarのuserInteractionEnableの状態で、pointの値に補正が入る
まず、UINavigationBarのhistTestは、「2度」呼ばれます。
そして2度目に呼ばれたときのpoint.yの値が、userInteractionEnableの状態で変わります。
userInterfactionEnable=NOの時は、一度目と二度目でpoint.yの値は同じです。
2014-08-16 18:07:23.846 HitTest[79584:60b] hitTest point.y=37.0 // NavigationBarの中でタップ、1度目
2014-08-16 18:07:23.849 HitTest[79584:60b] hitTest point.y=37.0 // NavigationBarの中でタップ、2度目
2014-08-16 18:07:26.692 HitTest[79584:60b] hitTest point.y=49.5 // NavigationBarの外でタップ、1度目
2014-08-16 18:07:26.693 HitTest[79584:60b] hitTest point.y=49.5 // NavigationBarの外でタップ、2度目
しかしuserInterfactionEnable=YESの時は、UINavigationBarの外側でのタップの場合、二度目のpoint.yの値が補正がかかっているようです。
2014-08-16 18:09:52.293 HitTest[79743:60b] hitTest point.y=37.0 // NavigationBarの中でタップ、1度目
2014-08-16 18:09:52.296 HitTest[79743:60b] hitTest point.y=37.0 // NavigationBarの中でタップ、2度目
2014-08-16 18:09:56.658 HitTest[79743:60b] hitTest point.y=49.0 // (A)NavigationBarの外でタップ、1度目
2014-08-16 18:09:56.659 HitTest[79743:60b] hitTest point.y=34.0 // (B)NavigationBarの外でタップ、2度目
この(A)が補正無しのpoint.yで、(B)が補正されたpoint.yです。NavigationBarの下のタップでは-15されるようです。この-15の補正が入るので、NavigationBarの真下でのタップもNavigationBarの「中」でのタップと認識させてるようです。
この補正、下だけでなくて「上」にも効いてるようです。
なんでこんな事してるのAppleさん
ユーザビリティを上げるために当たり判定を広げてのだとは思うのだけど、広げ方が「histTestに渡すpoint.yに補正を入れる」って作り方は勘弁してください分からなかったです。