这绝对令人困惑。在3.5英寸iPhone模拟器上,我的应用程序上的所有UIButton工作正常。但是,当我在4英寸iPhone模拟器上启动时,应用程序左侧的所有UIButton都不会收到任何点击事件。
以下是3.5英寸大小和4英寸大小的屏幕截图。在4“大小,我添加了一行。在该行的左边,没有任何按钮接收点击事件。在该行的右侧,所有按钮都表现正常。按钮2,5和8的左侧做不响应点击,但这些按钮的右侧确实响应。
UPDATE ---- 感谢@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的大小不正确吗?
答案 0 :(得分:8)
这是一个非常常见的问题:您的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];
}
};
编辑: 正如您在评论中提到的,罪魁祸首视图是主UIWindow,其大小为320x480而不是320x568。 在xib中启用“启动时全屏”修复此。
当然,问题是:“为什么?” :)
如果您在文本编辑器中提取xib文件,您会注意到宽度为320,高度为480的硬编码到窗口。当xib在启动时被解码时,窗口最初是用这个320x480帧构建的。
UIKit然后查询-[UIWindow resizesToFullScreen]
(私有方法)。如果返回YES,则UIWindow执行相当于[self setFrame:[[self window] bounds]]
的操作。
在Interface Builder中切换“启动时全屏”标志直接切换私有UIWindow.resizesToFullScreen
标志。
答案 1 :(得分:0)
让我猜一下,这只发生在横向模式中,对吧?
当我专门为iPhone-4S开发时,我在我的应用程序中遇到了同样的问题。但是当我开始在iPhone-5上进行测试时,底部触摸不起作用。这是frame
。确保frames
在代码和bounds
文件(如果有)中设置为XIB
。 frames
和bounds
文件中的不同man
/ xib
也可能导致此类行为。
我最终删除了xib
个文件,并以编程方式完成了所有操作。我学到的一件事是,用viewWillAppear
或viewDidAppear
方法而不是viewDidLoad
设置框架。另请查看frame
中的bounds
/ RootViewController
。最后一点,尽量不要为frames
使用常量值,使用与superview相关的参考帧。
PS,知道是否真的是导致此行为的帧/边界的一种方法是,为masksToBounds
设置YES
到views
。这样,您的观点就不会在他们的视野之外显现出来。