UIButton无法正确注册iPhone屏幕底部区域的触摸

我有一个应用程序,许多不同的button排列在一个像方形/矩形格式的计算器。 它实际上与默认的iOS计算器非常相似。 大约有6行,每列4个button。

问题

我遇到的问题涉及底部行中的button(大约在iPhone 4屏幕的底部10)。 当按下时,它们不能正常运行,必须按下并保持(大约在一秒钟之内)以注册“button按下”。 这与标准的短按。

除了这个底部行以外没有其他button以这种方式performance。

此外,如果这些button在其上边轻敲,则performance正常,只要触摸即可响应。 这使我相信,button本身不是问题,但我的意见的布局有一些问题。

还应该指出的是,这个问题只存在于物理设备上。 在模拟器上,button的行为正常。

上下文

包含这些button的视图不是应用程序的根视图控制器。 相反,它被转换为(在这里没有什么奇特的):

[self presentViewController:navController animated:YES completion:nil]; 

自我就是根视图控制器

我有问题的视图控制器包含在一个导航控制器中,并由上面可以看到的根视图控制器以模态方式呈现。

我到目前为止所尝试过的

  • 打开和closures自动布局:同样的问题

  • 重新排列视图的层次结构:我移动了所有其他视图之上和之后的有问题的button,结果相同:同样的问题

  • 多个设备(iPhone 4,4s,5):同样的问题(尽pipebutton在3.5英寸和4英寸模拟器上都能正常响应)

  • testing其他应用程序(当在这个区域的button被按下在其他应用程序,他们的行为正常)

附加信息

  • 一切都在Interface Builder中为有问题的视图控制器进行布置
  • 所有的button都是带有标准设置的系统button,除了文字之外,其他都完全一样。
  • 屏幕上的所有元素(button,标签等)都是“视图”的子视图,
  • button彼此齐平,不应该重叠超过一个或两个像素。
  • 有问题的button尺寸:80宽×高44。
  • 有问题的button与屏幕底部齐平
  • 除了button之外,还有一个UIImage和几个标签,但是这些标签位于屏幕的顶部,并且不以任何方式与任何button重叠。

这听起来像是button和UIScreenEdgePanGestureRecognizer(或其他任何东西)之间的交互,负责检测用户想要调用系统的控制中心。

实际上有两个潜在的问题:

  • 在针对您的应用的手势的可能性与针对系统的手势之间可能存在交互(即冲突)。 如果您有手势识别器,则可能必须使用委托方法在它们与系统的手势识别器之间进行调解。

  • 在靠近屏幕边缘的点击(即在屏幕边缘手势识别器的“区域”)中工作,但是它导致button在物理上不正常,即,即使在日志logging中它看起来不被轻敲表明它有(见我的答案在这里: https : //stackoverflow.com/a/22000692/341994 )。

这个问题的原因是,苹果似乎把一个GestureRecognizer放在屏幕的底部,在任何其他的视图延迟触摸。 在应用程序的窗口上摆弄手势识别器之后,我想出了一个包含UIButton子类的解决scheme:

 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { BOOL inside = [super pointInside: point withEvent: event]; if (inside && !self.isHighlighted && event.type == UIEventTypeTouches) { self.highlighted = YES; } return inside; } 

给定的方法被调用,虽然touchesBegan:被称为延迟。 检查视图是否位于屏幕的底部可能适合于防止此修复程序可能出现的任何副作用。

卢卡斯迅速回答,并取消选中

 extension UIButton { public override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool { var inside = super.pointInside(point, withEvent: event) if inside != highlighted && event?.type == .Touches { highlighted = inside } return inside } } 

我根据Luka的回答写了一个完整的解决scheme。 只要让任何冲突的button符合这个类,问题就会消失:

 class BorderBugFixButton : UIButton { override func awakeFromNib() { super.awakeFromNib() NSNotificationCenter.defaultCenter().addObserver(self, selector: "unHighlight", name: UIApplicationWillResignActiveNotification, object: nil) } deinit { NSNotificationCenter.defaultCenter().removeObserver(self) } override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool { let inside = super.pointInside(point, withEvent: event) if inside != highlighted && event?.type == .Touches { highlighted = inside } return inside } internal func unHighlight() { highlighted = false } } 

PS:对于那些不喜欢Storyboard / Xib的人,只需将awakeFromNib()的实现移植到init()

Swift 3解决scheme

 extension UIControl { open override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { let inside = super.point(inside: point, with: event) if inside != isHighlighted && event?.type == .touches { isHighlighted = inside } return inside } } 

在处理更旧的故事板到iOS 7+的时候,我经常遇到这样的情况,通常当有问题的ViewController有一个UIScrollView的forms的时候。 在ViewController对象(不是视图,黄色圆圈的视图)中仔细检查这两个设置。 当我取消选中顶部和底部小节下方的“延伸边缘”时,scrollView的框架向下调整了64点(导航和状态栏的高度)。

UIButton不能在屏幕的底部工作 将NavBar.bottom和scrollView.top之间的空间设置回0后,button开始工作。 这可能是由于scrollView.frame.bottom是在窗口底部以上64像素的事实,所以在该区域的触摸被忽略,因为它们在技术上不在scrollView的框架中,但由于某种原因仍然在视觉上显示。

iOS 9.3,Xcode 7.3

我build议你应该为实现Lukas的答案的UIButton类做一个类别。 有关如何创build类别的说明,请参阅此post: 如何在Xcode 6或更高版本中创build类别?

用传统的“+”号给它一个合适的名字,也就是说,如果你把它命名为“BottomOfScreen”,那么结果文件名将是“UIButton + BottomOfScreen”。

如果你使用的是Objective-C,那么你会得到一个新的类别的* .h和* .m文件。

*。H

 #import <UIKit/UIKit.h> @interface UIButton (BottomOfScreen) @end 

* .M

 #import "UIButton+BottomOfScreen.h" @implementation UIButton (BottomOfScreen) - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { BOOL inside = [super pointInside:point withEvent:event]; if (inside && !self.isHighlighted && (event.type == UIEventTypeTouches)) { self.highlighted = true; } else { nil; } return inside; } @end