【发布时间】:2014-11-17 01:50:25
【问题描述】:
我有一个容器UIView。其子项的位置通过自动布局进行管理。但是,我想明确定位容器本身。
容器存在于我称之为VideoPreviewView 的UIView 子类中。容器名为contentOverlayView。
这是我将一个明显的红色子元素添加到填充它的容器的代码,除了边缘的 1 像素边距:
UIView *const redView = [UIView new];
[redView setTranslatesAutoresizingMaskIntoConstraints: NO];
[redView setBackgroundColor: [UIColor redColor]];
[[videoView contentOverlayView] addSubview: redView];
[[videoView contentOverlayView] addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:@"H:|-(1@900)-[redView]-(1@900)-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(redView)]];
[[videoView contentOverlayView] addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:@"V:|-(1@900)-[redView]-(1@900)-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(redView)]];
在layoutSubviews中设置框架
我最初将容器视图定位在其中的方法是简单地覆盖 layoutSubviews 为 VideoPreviewView 并在那里显式设置容器的框架,如下所示:
-(void) layoutSubviews
{
// Other stuff snipped out.
const CGRect videoBounds = [self videoBounds];
[_contentOverlayView setFrame: videoBounds];
[super layoutSubviews];
}
……但这不起作用。如果我在videoView 上使用recursiveDescription,我会得到:
<VideoPreviewView: 0x146a54f0; frame = (0 0; 320 460); layer = <CALayer: 0x146a5640>>
| <UIView: 0x145b6610; frame = (0 0; 2 2); layer = <CALayer: 0x145b6680>>
| | <UIView: 0x145bff60; frame = (1 1; 0 0); layer = <CALayer: 0x145bffd0>>
它的宽度刚好可以满足我需要的边距,但是位置完全错误,而且框架没有我想要的那么大。
我在容器视图上使用了_autoLayoutTrace 来尝试解决这个问题,但我被告知布局不明确:
UIWindow:0x145a3a50
| UIView:0x145a6e60
| | HPBezelView:0x1468d580
| | | UIImageView:0x145aab30
| | *VideoPreviewView:0x146a54f0
| | | *UIView:0x145b6610- AMBIGUOUS LAYOUT for UIView:0x145b6610.minX{id: 5}, UIView:0x145b6610.minY{id: 13}, UIView:0x145b6610.Width{id: 8}, UIView:0x145b6610.Height{id: 16}
| | | | *UIView:0x145bff60- AMBIGUOUS LAYOUT for UIView:0x145bff60.minX{id: 4}, UIView:0x145bff60.minY{id: 12}, UIView:0x145bff60.Width{id: 9}, UIView:0x145bff60.Height{id: 17}
这告诉我,如果我使用自动布局,框架会被忽略,所以我也需要使用自动布局来设置容器的框架。
添加大小限制
其他一些帖子和博客等也建议采取这种行动。所以我加了一些约束来控制容器的宽高:
_contentOverlayWidthConstraint =
[NSLayoutConstraint constraintWithItem: contentOverlayView
attribute: NSLayoutAttributeWidth
relatedBy: NSLayoutRelationEqual
toItem: nil
attribute: NSLayoutAttributeNotAnAttribute
multiplier: 1.0
constant: 1];
_contentOverlayHeightConstraint =
[NSLayoutConstraint constraintWithItem: contentOverlayView
attribute: NSLayoutAttributeHeight
relatedBy: NSLayoutRelationEqual
toItem: nil
attribute: NSLayoutAttributeNotAnAttribute
multiplier: 1.0
constant: 1];
[contentOverlayView addConstraints: @[_contentOverlayWidthConstraint, _contentOverlayHeightConstraint]];
我更新了我的 layoutSubviews 方法来调整这些约束的“常量”:
-(void) layoutSubviews
{
const CGRect videoBounds = [self videoBounds];
[_contentOverlayView setFrame: videoBounds];
[_contentOverlayWidthConstraint setConstant: CGRectGetWidth(videoBounds)];
[_contentOverlayHeightConstraint setConstant: CGRectGetHeight(videoBounds)];
[super layoutSubviews];
}
这工作得更好一些——红色视图现在可见并且大小正确,但它仍然位于错误的位置。我仍然从跟踪中得到歧义:
UIWindow:0x17d76a00
| UIView:0x17d7dfd0
| | HPBezelView:0x17d7d7c0
| | | UIImageView:0x17d82240
| | *VideoPreviewView:0x17d925e0
| | | UIView:0x17d96790
| | | *UIView:0x17d96830- AMBIGUOUS LAYOUT for UIView:0x17d96830.minX{id: 9}, UIView:0x17d96830.minY{id: 16}
| | | | *UIView:0x17d9ae90- AMBIGUOUS LAYOUT for UIView:0x17d9ae90.minX{id: 8}, UIView:0x17d9ae90.minY{id: 15}
……所以,宽度和高度的歧义已经消失,但位置的歧义仍然存在。
添加位置约束
所以,我又添加了两个布局约束来设置容器的位置:
_contentOverlayLeftConstraint =
[NSLayoutConstraint constraintWithItem: contentOverlayView
attribute: NSLayoutAttributeLeft
relatedBy: NSLayoutRelationEqual
toItem: nil
attribute: NSLayoutAttributeNotAnAttribute
multiplier: 1.0
constant: 0];
_contentOverlayTopConstraint =
[NSLayoutConstraint constraintWithItem: contentOverlayView
attribute: NSLayoutAttributeTop
relatedBy: NSLayoutRelationEqual
toItem: nil
attribute: NSLayoutAttributeNotAnAttribute
multiplier: 1.0
constant: 0];
[contentOverlayView addConstraints: @[_contentOverlayLeftConstraint, _contentOverlayTopConstraint]];
并更新layoutSubviews:
-(void) layoutSubviews
{
[[self contentView] setFrame: [self bounds]];
[[self videoPreviewLayer] setFrame: [self bounds]];
const CGRect videoBounds = [self videoBounds];
[_contentOverlayWidthConstraint setConstant: CGRectGetWidth(videoBounds)];
[_contentOverlayHeightConstraint setConstant: CGRectGetHeight(videoBounds)];
[_contentOverlayLeftConstraint setConstant: CGRectGetMinX(videoBounds)];
[_contentOverlayTopConstraint setConstant: CGRectGetMinY(videoBounds)];
[super layoutSubviews];
}
崩溃
但是当我尝试添加新的约束时,我得到一个错误的异常:
* 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“* +[NSLayoutConstraint constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:]: 不能做出这样的约束设置一个等于常数的位置。位置属性必须成对指定'
这个我完全不明白。我不知道如何纠正这个问题。
你能帮忙吗?
【问题讨论】:
标签: ios uikit autolayout