为啥 UIView 的这些自动布局约束会阻止 UIButton 子视图接收触摸事件?
Posted
技术标签:
【中文标题】为啥 UIView 的这些自动布局约束会阻止 UIButton 子视图接收触摸事件?【英文标题】:Why do these Auto Layout constraints for a UIView prevent UIButton subviews from receiving touch events?为什么 UIView 的这些自动布局约束会阻止 UIButton 子视图接收触摸事件? 【发布时间】:2015-08-07 15:21:50 【问题描述】:我正在以编程方式使用自动布局。我有一个简单的UIViewController
和一些控件,包括并排排列的两个UIButton
s。我经常将相关控件分组到 UIView
中,作为容器,使 groups-of-controls 的排列更易于管理。您将在下面看到 _iapButtonsView
,它包含两个按钮和一些垫片。
我的问题。在以下示例中,我被我认为是对约束的有效更改所吸引,这实际上导致UIButton
s 没有接收触摸事件。
代码提取 - 按钮确实接收触摸事件的约束:
- (void)viewDidLoad
[super viewDidLoad];
...
_buyButton = [ViewCreationHelper createRoundedBorderButtonBold];
[_buyButton addTarget:self action:@selector(buyTap:) forControlEvents:UIControlEventTouchUpInside];
_restoreButton = [ViewCreationHelper createRoundedBorderButton];
[_restoreButton addTarget:self action:@selector(restorePurchaseTap:) forControlEvents:UIControlEventTouchUpInside];
_iapButtonsView = [UIView new];
_iapButtonsView.translatesAutoresizingMaskIntoConstraints = NO;
[contentView addSubview:_iapButtonsView];
...
[_iapButtonsView addSubview:_buyButton];
[_iapButtonsView addSubview:_restoreButton];
// Constraints
NSDictionary* views = NSDictionaryOfVariableBindings(scrollView, contentView, iapDesciption, _iapButtonsView, _buyButton, _restoreButton, spacer1, spacer2, spacer3);
...
constraints = [NSLayoutConstraint
constraintsWithVisualFormat:@"V:|-25-[iapDesciption]-40-[_iapButtonsView]|"
options:0
metrics:nil
views:views];
[contentView addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[_iapButtonsView]-20-|" options:0 metrics:nil views:views];
[contentView addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[spacer1][_buyButton(==120.0)][spacer2(==spacer1)][_restoreButton(==_buyButton)][spacer3(==spacer1)]|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:views];
[_iapButtonsView addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_buyButton(==80.0)]|" options:0 metrics:nil views:views];
[_iapButtonsView addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_restoreButton(==80.0)]|" options:0 metrics:nil views:views];
[_iapButtonsView addConstraints:constraints];
...
有问题的约束是_iapButtonsView
的垂直约束。在开发过程中(这是一个应用内购买屏幕)我在底部有一些 debug 控件,这就是为什么我将尾随 |
连接到超级视图的底部边缘,如下所示:
constraintsWithVisualFormat:@"V:|-25-[iapDesciption]-40-[_iapButtonsView][someSpacer][someControls]|"
当我取出那些 debug 控件时,我将这些约束更改为:
constraintsWithVisualFormat:@"V:|-25-[iapDesciption]-40-[_iapButtonsView]"
认为这更正确:它们是从顶部锚定的,只有 _iapButtonsView
从它的子视图(主要是两个按钮)获取它的大小,所以我不应该连接到底部边缘的superview...
进行该更改后,按钮不再接收触摸事件。为了进行实验,我尝试显式设置_iapButtonsView
的垂直大小,但仍然没有连接到超级视图的底部边缘,例如
constraintsWithVisualFormat:@"V:|-25-[iapDesciption]-40-[_iapButtonsView(==80.0)]"
有了这些限制,按钮仍然不会接收到触摸事件。
我不明白什么?
(编辑:根据 daddy warbucks 的建议,我删除了上面代码中重复的 [contentView addSubview:_iapButtonsView];
)
【问题讨论】:
我经常遇到意外地将视图的宽度或高度更改为 0 的约束。你能设置_iapButtonsView.clipsToBounds = YES
看看这是否揭示了问题吗?如果是这样,您的按钮应该会消失。
感谢您的建议。我会试一试,虽然我已经尝试给 _iapButtonsView 一个背景颜色......它显示为预期的大小。
这也说明了 iabButtonsView 的问题。也许是按钮本身在改变大小。
@DanLoughney - 我试过_iapButtonsView.clipsToBounds = YES
,但没有发现问题。与其他实验一起,我认为 _iapButtonsView
的大小是正确的...只是不确定为什么限制会导致没有触摸事件通过...谢谢。
【参考方案1】:
一个问题,你已经调用了两次:
[contentView addSubview:_iapButtonsView];
不确定这是否有帮助,但这可能是个问题。
另外,你不必使用“(==80.0)”,只需使用“(80.0)”,甚至“(80)”不确定这是否有帮助,但是嘿,它可以,对吧?
【讨论】:
很好看。我认为双[contentView addSubview:_iapButtonsView];
只是我编辑问题中的代码提取时出现的错误,但实际上我在完整的 viewDidLoad
方法中调用了两次。不幸的是,删除重复调用并不能纠正/回答我看到的行为,更苗条的(==80)
建议也不能。感谢现场和建议;)
我还假设您的垫片的属性 translatesAutoresizingMaskIntoConstraints 也设置为“NO”,对吗?并且每一次机会,是包含嵌套在 UIScrollView 中的按钮的 UIView 吗?此外,您是否尝试过将选项“options:NSLayoutFormatAlignAllCenterY”设置为“options:0”?我只使用编程视图进行编程,我的代码通常最终每个视图都有一千行代码,具体取决于复杂性,而且我从未使用过“NSLayoutFormat ...”选项,这只是一个猜测,但也许值得一试.我总是将选项设置为“选项:0”
我也会改变这个“[_iapButtonsView addConstraints:constraints];”对此:“[_iapButtonsView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@”H:|-20-[_iapButtonsView]-20-|”options:0 metrics:nil views:views]];”并删除这些行:“ [_iapButtonsView addConstraints:constraints];”您可以添加这些约束,而无需先将它们设置为变量“约束”
啊,还有,我想这会成功,我现在记得为什么会这样,你必须添加这个“ [_buyButton addTarget:self action:@selector(buyTap:) forControlEvents: UIControlEventTouchUpInside];"仅在添加约束后,看看是否有帮助
@Loxx 你救了我!感谢您为我节省了很多时间来尝试解决 AutoLayout“歧义”或错误边界问题。我沿着这条路走了一点,但我决定尝试您的建议,即在创建约束之后添加事件,瞧!现在一切正常。以上是关于为啥 UIView 的这些自动布局约束会阻止 UIButton 子视图接收触摸事件?的主要内容,如果未能解决你的问题,请参考以下文章
Interface Builder 运行时自动布局约束阻止视图占用固有大小,我该如何解决这个问题?
向添加到 UIWindow 的视图添加约束时,为啥无法设置自动布局约束?