当将UIButton设置为UITextField的leftView时,UIButton会在边界外接收触摸事件。

3
这对我来说有些费解。在我建立的一个应用程序中,我使用了一个UITextField,并将一个按钮添加为其leftView属性。然而,在iPad上(无论是模拟器还是实际设备),按钮会接收到超出其边界范围外的触摸事件。这会干扰UITextField成为第一响应者的能力,当用户触摸占位符文本时。似乎触摸占位符文本时,事件被按钮处理而不是文本字段本身。奇怪的是,这只出现在iPad上;在iPhone上,它按预期工作。
下面是一些简单的代码,演示了这个问题:
- (void)viewWillLayoutSubviews {

    [super viewWillLayoutSubviews];

    UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10.0f,
                                                                           10.0f,
                                                                           (self.view.frame.size.width - 20.0f),
                                                                           35.0f)];
    textField.borderStyle = UITextBorderStyleRoundedRect;
    textField.placeholder = @"Test text";
    [self.view addSubview:textField];

    UIButton *addButton = [UIButton buttonWithType:UIButtonTypeContactAdd];
    [addButton addTarget:self action:@selector(touchDown:) forControlEvents:UIControlEventTouchDown];
    [addButton addTarget:self action:@selector(touchUpInside) forControlEvents:UIControlEventTouchUpInside];
    [addButton addTarget:self action:@selector(touchUpOutside) forControlEvents:UIControlEventTouchUpOutside];
    textField.leftView = addButton;
    textField.leftViewMode = UITextFieldViewModeAlways;    
}

- (void)touchDown:(id)sender {
    NSLog(@"touchDown");
}

- (void)touchUpInside {
    NSLog(@"touchUpInside");
}

- (void)touchUpOutside {
     NSLog(@"touchUpOutside");
 }

看起来有时候触摸似乎仍然被视为在按钮范围内,即使它们表现为在按钮范围外。随后向右移动,该按钮仅接收UIControlEventTouchDown和UIControlEventTouchUpOutside事件。

2013-07-25 11:51:44.217 TestApp[22722:c07] touchDown
2013-07-25 11:51:44.306 TestApp[22722:c07] touchUpInside
2013-07-25 11:51:44.689 TestApp[22722:c07] touchDown
2013-07-25 11:51:44.801 TestApp[22722:c07] touchUpOutside

编辑 这里是一个例子,展示了按钮的背景颜色更改以及触发上述事件的大致区域。我检查了按钮的框架,它的宽度小于30px。

示例图片


改变按钮的背景颜色并查看它填充文本视图的情况,然后根据此设置框架。如果这种方式不起作用,则可以创建一个按钮子类,并使用所有uiview类的“point in side”方法来查看其位置。如果位置是奇数或负数,则从该函数返回NO。虽然这并没有回答你的问题,但它可能会有所帮助。 - A'sa Dickens
尝试使用buttonWithType Custom,并为按钮设置框架;这样您就可以控制按钮的尺寸,无论uibuttontypecontactadd的框架是否已知。对于iPhone / iPad上的此类按钮,可能有不同的框架,因此会有不同的行为。 - Durican Radu
感谢建议,但我已经检查了框架,似乎没有匹配。 它只有大约30像素宽。 我已经添加了一个屏幕截图,更改了按钮的背景颜色,并显示了触发这些事件的大致区域。 我可能最终会选择对UIButton或UITextField进行子类化来尝试纠正行为,但是想先看看是否完全错过了什么。 不知道这是否只是UITextField的一个错误。 - Kevin Lord
3个回答

4

昨晚我花了更多时间来处理这个问题。在我的实际应用程序中,我已经创建了UITextField的子类,所以我最终重写了-(id)hitTest:withEvent:方法,如下所示。到目前为止,这种做法一直很有效。

- (id)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

    if ([[super hitTest:point withEvent:event] isEqual:self.leftView]) {
        if (CGRectContainsPoint(self.leftView.frame, point)) {
            return self.leftView;
        } else {
            return self;
        }
    }

    return [super hitTest:point withEvent:event];
}

1

我也遇到了这个问题,找到了另一种解决方案,即添加一个检查,判断事件点是否位于按钮内部。

- (void)touchUpInside:(UIButton *)sender event:(UIEvent *)event
{
    CGPoint location = [[[event allTouches] anyObject] locationInView:sender];

    if (!CGRectContainsPoint(sender.bounds, location)) {
        // Outside of bounds, so ignore:
        return;
    }
    // Inside our bounds, so continue as normal:
}

1
我核实了你的结果。我认为这很可能是UITextView中的一个bug。不幸的是,由于某种原因,如果你设置了leftView,那么该区域中的事件会被发送到错误的视图(在iPad上)。
我没有一个简单的解决方法,因为调整leftView的帧没有效果。我认为它需要在我们无法访问的更低级别上进行修复。也许报告这个bug给苹果,现在只能忍受它?
你可以跟踪触摸的位置并忽略它,如果超出边界的话,但这似乎是为了一个小bug而做很多工作?

1
谢谢 - 感谢确认。我通过覆盖 -(id)hitTest:withEvent: 很容易地修复了这个行为,我在下面的答案中详细说明了。 - Kevin Lord

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接