无法点击 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
文件(如果有)中都设置为 bounds
。 man
和 xib
文件中的不同 frames
/bounds
也可能导致此类行为。
我最终删除了xib
文件,并以编程方式完成了所有操作。我学到的一件事是,将框架设置为 viewWillAppear
或 viewDidAppear
方法而不是 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”按钮?