UIButton未能在iPhone屏幕的底部区域正确注册触摸

问题描述 投票:28回答:8

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

问题

我遇到的问题涉及底行中的按钮(大约是iPhone 4屏幕的底部10)。当按下它们时,它们不能正常工作,按下它们时必须按住它们(大约不到一秒钟)以注册“按下按钮”。这与标准短抽头相反。

除此底行之外没有其他按钮以这种方式运行。

此外,如果这些按钮在其上边缘轻敲,它们会表现正常,一旦触摸就会响应。这让我相信按钮本身不是问题,但是我的视图布局存在一些问题。

还应注意,该问题仅存在于物理设备上。在模拟器上,按钮表现正常。

上下文

包含这些按钮的视图不是应用程序的根视图控制器。相反,它转变为如此(这里没什么特别的):

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

self是根视图控制器

我遇到问题的视图控制器包含在导航控制器中,并由根视图控制器以模态方式显示,您可以在上面看到。

到目前为止我尝试过的

  • 打开和关闭自动布局:同样的问题
  • 重新排列视图层次结构:我将有问题的按钮移动到所有其他视图的顶部和后面,结果相同:同样的问题
  • 多个设备(iPhone 4,4s,5):同样的问题(虽然按钮在3.5英寸和4英寸模拟器上都能正常响应)
  • 测试其他应用程序(当在其他应用程序上按下此区域中的按钮时,它们的行为正常)

附加信息

  • 在Interface Builder中为有问题的视图控制器布局了所有内容
  • 所有按钮都是带有标准设置的系统按钮,除了文本外,它们都完全相同。
  • 屏幕的所有元素(按钮,标签等)都是“视图”的子视图
  • 按钮彼此齐平,不应超过一个或两个像素。
  • 有问题的按钮具有尺寸:80宽度X 44高度。
  • 有问题的按钮与屏幕底部齐平
  • 除了按钮之外,还有一个UIImage和几个标签,但是它们位于屏幕的顶部,并且不会以任何方式与任何按钮重叠。
ios objective-c uibutton interface-builder
8个回答
17
投票

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

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

  • 针对您的应用的手势的可能性与针对系统的手势之间可能存在交互(即冲突)。如果您有手势识别器,则可能必须使用委托方法在它们与系统的手势识别器之间进行调解。
  • 有一个完善的错误,屏幕边缘附近的一个点击(即在屏幕边缘手势识别器的“区域”)工作,但它导致按钮在物理上行为不端,即它看起来好像已被点击即使记录表明它有(见我的答案:https://stackoverflow.com/a/22000692/341994)。

31
投票

导致此问题的原因是Apple似乎在屏幕底部放置了一个GestureRecognizer,可以延迟任何其他视图中的触摸。在App的窗口上摆弄手势识别器后,我想出了一个包含UIButton子类的解决方案:

- (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:被称为延迟,但调用给定的方法。检查视图是否位于屏幕底部可能适合于防止此修复可能出现的任何副作用。


7
投票

快速回答Lukas并取消选择突出显示

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

  }

}

5
投票

Swift 3解决方案

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
    }
}

4
投票

我已根据Luka's的答案在swift中写了一个完整的解决方案。只需使任何冲突按钮符合此类,问题就会消失:

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
    }

}

P.S。:对于那些不喜欢Storyboards / Xib的人,只需将awakeFromNib()的实现迁移到init()


0
投票

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

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


0
投票

iOS 9.3,Xcode 7.3

我建议您应该为实现Lukas' answer的UIButton类创建一个类别。有关如何创建类别的说明,请参阅此帖子:How do I create a category in Xcode 6 or higher?

使用传统的“+”符号为其指定一个合适的名称,即如果将其命名为“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

0
投票

我能够通过在delaysTouchesBegan中禁用viewWillAppear来解决这个问题

self.navigationController?.interactivePopGestureRecognizer?.delaysTouchesBegan = false
© www.soinside.com 2019 - 2024. All rights reserved.