这是一个很常见的问题:您的 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 标志。