无法点击 4" iPhone 左侧的按钮

Posted

技术标签:

【中文标题】无法点击 4" iPhone 左侧的按钮【英文标题】:Can't tap buttons on the left side of 4" iPhone 【发布时间】:2013-09-25 04:19:53 【问题描述】:

这绝对令人困惑。在 3.5" iPhone 模拟器上,我的应用程序上的所有 UIButtons 都可以正常工作。但是,当我在 4" iPhone 模拟器上启动时,应用程序左侧的所有 UIButtons 都不会收到任何点击事件。

以下是 3.5" 尺寸和 4" 尺寸的屏幕截图。在 4" 尺寸上,我添加了一条线。在该线的左侧,没有任何按钮接收点击事件。在该线的右侧,所有按钮都正常运行。按钮 2、5 和 8 的左侧可以不响应点击,但这些按钮的右侧会响应。

更新---- 感谢@iccir,我发现了更多信息。显然,我的 UIWindow 只是 320x480 而不是应该的 568x320。我没有在我的代码中触摸 UIWindow,只是让它成为关键和可见的。在我的 MainWindow.xib 中,我将其 IBOutlet 连接到我的 rootViewController。

<UIWindow: 0xc097d50; frame = (0 0; 320 480); opaque = NO; autoresize = RM+BM; gestureRecognizers = <NSArray: 0xc098460>; layer = <UIWindowLayer: 0xc097e70>>

我大吃一惊。知道为什么 UIWindow 的大小不正确吗?

【问题讨论】:

我认为这是帧大小的问题。因此,请尝试检查视图大小(将按钮添加到哪个视图,检查视图框架) 在设备上试一试,然后再尝试其他任何东西.. 我没有用于设备测试的 iPhone 5。 如果您发布一些添加按钮的代码,可能会更容易提供帮助 - 或者有关 xib 的一些信息,如果您正在使用它。 @matsr 所有按钮都是 xib 的一部分,我没有以编程方式添加任何按钮。 【参考方案1】:

这是一个很常见的问题:您的 UIButton 超出了它的一个超级视图的范围。如果 clipsToBounds/masksToBounds 设置为 NO(默认值),您的 UIButton 仍会显示,但不会向其发送触摸事件。

让我们简化一下这个案例。假设一个视图控制器的代码如下:

- (void) viewDidLoad

    [super viewDidLoad];

    UIColor *fadedRedColor  = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.25];
    UIColor *fadedBlueColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.25];

    CGRect containerFrame = CGRectMake(25,  25,  100, 100);
    CGRect buttonFrame    = CGRectMake(100, 100, 64,  44);

    UIView *container = [[UIView alloc] initWithFrame:containerFrame];

    UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
    [button setTitle:@"Button" forState:UIControlStateNormal];
    [button setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [button setFrame:buttonFrame];
    [button addTarget:self action:@selector(_handleButton:) forControlEvents:UIControlEventTouchUpInside];

    [container setBackgroundColor:fadedRedColor];
    [button    setBackgroundColor:fadedBlueColor];

    [container addSubview:button];

    [[self view] addSubview:container];


- (void) _handleButton:(id)sender

    NSLog(@"Moooooo!");

看起来像这样:

按钮包含在 container 中,但它位于容器边界之外(容器宽 100 像素,高 100 像素,按钮的原点位于 100, 100)。

当您触摸屏幕时,UIKit 将从视图层次结构的顶部 (UIWindow) 开始并递归调用 -[UIView hitTest:withEvent:] 直到找到应该处理触摸的视图。然而,在这个例子中,UIKit 永远不会下降到容器中(因为你触摸了它的边界之外),因此按钮子视图不会被点击。

如果我们改为将buttonFrame 更改为50, 50,它看起来像这样:

按钮与容器重叠的部分会响应触摸事件。位于容器外部的部分不会:

要调试不能完全触摸的视图,您可以尝试如下调试功能:

static void sDebugViewThatIsntTouchable(UIView *view)

    UIView *superview = [view superview];

    while (superview) 
        CGRect rectInSuperview = [view convertRect:[view bounds] toView:superview];

        CGPoint topLeft     = CGPointMake(CGRectGetMinX(rectInSuperview), CGRectGetMinY(rectInSuperview));
        CGPoint topRight    = CGPointMake(CGRectGetMaxX(rectInSuperview), CGRectGetMinY(rectInSuperview));
        CGPoint bottomLeft  = CGPointMake(CGRectGetMinX(rectInSuperview), CGRectGetMaxY(rectInSuperview));
        CGPoint bottomRight = CGPointMake(CGRectGetMaxX(rectInSuperview), CGRectGetMaxY(rectInSuperview));

        if (![superview pointInside:topLeft withEvent:nil]) 
            NSLog(@"Top left point of view %@ not inside superview %@", view, superview);
        

        if (![superview pointInside:topRight withEvent:nil]) 
            NSLog(@"Top right point of view %@ not inside superview %@", view, superview);
        

        if (![superview pointInside:bottomLeft withEvent:nil]) 
            NSLog(@"Bottom left point of view %@ not inside superview %@", view, superview);
        

        if (![superview pointInside:bottomRight withEvent:nil]) 
            NSLog(@"Bottom right point of view %@ not inside superview %@", view, superview);
        

        superview = [superview superview];
    
;

编辑: 正如您在 cmets 中提到的,罪魁祸首是主 UIWindow,它的大小为 320x480 而不是 320x568。 在 xib 中打开“启动时全屏显示”修复了此问题

当然,问题是:“为什么?” :)

如果您在文本编辑器中打开您的 xib 文件,您会注意到窗口的宽度为 320,高度为 480。当 xib 在启动时被解码时,窗口最初是用这个 320x480 帧构建的。

UIKit 然后查询-[UIWindow resizesToFullScreen](私有方法)。如果返回 YES,则 UIWindow 的作用相当于 [self setFrame:[[self window] bounds]]

在 Interface Builder 中切换“启动时全屏”标志会直接切换私有 UIWindow.resizesToFullScreen 标志。

【讨论】:

这个功能很完美,谢谢!事实证明,我的self.view 的大小是正确的,但 UIWindow 是 320x480!所以..这到底是怎么回事?我会继续寻找。 您是在代码中还是在 xib/storyboard 中手动创建 UIWindow?如果手动,则需要使用[[UIScreen mainScreen] bounds]-applicationFrame 作为窗口框架,而不是硬编码值。 我正在使用由 Xcode 生成的旧 MainWindow.xib。 考虑到 MainWindow.xib 大概是 3 年前由 Xcode 生成的,我决定在 Xcode 中查看它的所有设置。我注意到没有检查“启动时全屏”,并发现这些文档表明应该始终检查它:developer.apple.com/library/ios/documentation/windowsviews/…我检查了它,重新运行,所有这些按钮现在都可以工作了!请在您的答案中包含有关 MainWindow.xib 的一些信息,我将奖励您!谢谢! 已添加!我通常不使用 xibs,所以我不得不做一些探索来弄清楚那个复选框控制的是什么。 :)【参考方案2】:

让我猜猜,这只会在横向模式下发生,对吧? 当我专门为 iPhone-4S 开发时,我的应用程序中遇到了同样的问题。但是当我开始在 iPhone-5 上进行测试时,底部的触摸不起作用。那是frame。确保 frames 在代码和 XIB 文件(如果有)中都设置为 boundsmanxib 文件中的不同 frames/bounds 也可能导致此类行为。

我最终删除了xib 文件,并以编程方式完成了所有操作。我学到的一件事是,将框架设置为 viewWillAppearviewDidAppear 方法而不是 viewDidLoad。还要检查RootViewController 中的frame/bounds。最后一件事,尽量不要对frames 使用常量值,对超级视图使用参考框架。

PS,了解是否真的是导致此行为的帧/边界的一种方法是将masksToBounds 设置为YES,用于views。这样,您的视图将不会在其矩形之外可见。

【讨论】:

我根本没有以编程方式设置我的框架,它们是在加载 xib 时自动设置的。我已经验证了视图是 568x320。卡片(UIButtons)直接添加到主视图中,不在超级视图之外。例如,我无法点击的卡片之一是 (18, 60) 50x64。 @iccir 的答案是正确的。这将是我的第二个建议。在AppDelegate 文件中的applicationDidFinishLaunching 方法中,您应该相应地设置applicationFrame。一个不错的选择是使用[UIScreen mainScreen].bounds,但您可能想检查它在 iOS7 上的行为。我还没有迁移到 XCode5/iOS7,所以不能确定。

以上是关于无法点击 4" iPhone 左侧的按钮的主要内容,如果未能解决你的问题,请参考以下文章

Instruments:UI Automation:iPhone app - 如何使用 NSRect 的参数点击“null”按钮?

PopOver 左侧向上打开+iphone

Iphone:点击/点击“开始”按钮后,虚拟键盘不会隐藏

iPhone 应用程序按钮样式,例如“添加到主屏幕”按钮

idea运行按钮是灰色无法点击

JS或Jquery动态改变导航栏样式