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