2

这绝对令人困惑。在 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 的大小不正确吗?

4

2 回答 2

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!");
}

看起来像这样: 截图 1

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

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

如果我们改为将 更改buttonFrame50, 50,它看起来像这样: 截图 2

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

截图 3

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

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标志。

于 2013-09-30T01:51:46.930 回答
0

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

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

PS,知道是否真的是负责此行为的框架/边界的一种方法是将 设置masksToBoundsYES,为views. 这样,您的视图将不会在其矩形之外可见。

于 2013-09-29T20:41:20.743 回答