UIView 不遵守 UIScrollView 中的自动布局约束
Posted
技术标签:
【中文标题】UIView 不遵守 UIScrollView 中的自动布局约束【英文标题】:UIView not obeying autolayout constraints in UIScrollView 【发布时间】:2013-07-21 13:48:03 【问题描述】:我将 UIView 添加到 UIScrollView
并对其进行约束,使其填充水平空间,除了一些边距。我的视觉约束如下所示:
@"|-16-[theLineView]-16-|"
我已将视图设置为一个像素高,因此它将显示为一条线,并将其放置在两个文本标签之间:
@"V:[someOtherStuff]-[aTextLabel]-[theLineView]-[anotherLabel]"
但是,我发现线条的宽度只会扩大到其上方/下方最长标签的宽度。
为什么会这样?
P.S 我读过这个http://developer.apple.com/library/ios/#technotes/tn2154/_index.html
代码
这里是来自一个测试项目的完整视图控制器代码,该项目在 iPad sim 上展示了这个问题。
- (void)viewDidLoad
[超级viewDidLoad];
self.scrollView = [[UIScrollView alloc] init];
self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
self.scrollView.backgroundColor = [UIColor greenColor];
[self.view addSubview:self.scrollView];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[scrollView]|"
options:0
metrics:0
views:@@"scrollView":self.scrollView]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|"
options:0
metrics:0
views:@@"scrollView":self.scrollView]];
self.line1 = [[UIView alloc] init];
self.line2 = [[UIView alloc] init];
self.label1 = [[UILabel alloc] init];
self.label2 = [[UILabel alloc] init];
self.label3 = [[UILabel alloc] init];
for (UILabel *label in @[self.label1, self.label2, self.label3])
label.text = @"I am a label and I am long enough that I can be multiline on an iphone but single on ipad";
for (UIView *view in @[self.line1, self.line2, self.label1, self.label2, self.label3])
view.translatesAutoresizingMaskIntoConstraints = NO;
view.backgroundColor = [UIColor redColor];
[self.scrollView addSubview:view];
//horizontal layout - all views/labels should fill the horizontal space expect for margin
for (UIView *view in @[self.line1, self.line2, self.label1, self.label2, self.label3])
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-16-[view]-16-|"
options:0
metrics:0
views:@@"view":view];
[self.scrollView addConstraints:constraints];
//vertical layout - stack em up
[self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[lab1]-[line1(==1)]-[lab2]-[line2(==1)]-[lab3]-|"
options:0
metrics:0
views:@@"lab1":self.label1, @"line1":self.line1, @"lab2":self.label2, @"line2":self.line2, @"lab3":self.label3]];
【问题讨论】:
你的1pxUIView
还有其他限制吗?
[view] 和[theLineView] 是同一个视图吗?您在 options 参数中有任何对齐选项设置吗?
options 参数中没有其他约束或任何内容。我会看看我是否可以在测试项目中重现。是的,这些观点是相同的,更正了 sn-p。
见这里:***.com/questions/16843633/…
【参考方案1】:
UIScrollView 会自动缩小以适应其中的视图。您需要在某处绝对设置宽度。
推荐战术:
-
使用约束(前导、尾随、顶部、底部)将滚动视图完全固定在其父视图内。
在 UIScrollView 中创建一个 UIView 并将您需要的所有内容放入其中。
设置约束,以便 UIView 将充当内容视图(这意味着它足够大以包含所有元素)。大量使用固有的内容大小、抗收缩性和带有约束的元素链接。生成的布局必须定义明确且唯一(这意味着如果您要移除外部的所有约束,布局仍然可以工作)。
将 UIView 的边界与其父视图(这是 UIScrollView 的实际内容视图,而不是 UIScrollView!)连接起来。
如果您在 interface-builder 中执行此操作(这是可能的),您需要在每次触摸该场景中的某些内容时重新检查您的约束。触摸我的意思是“选择”不仅仅是“修改”。
【讨论】:
对我不起作用,如何设置 UIView 以填满滚动视图的整个宽度? 正如我所说:contentView 总是填满整个scrollView,因为scrollView 会缩小。你必须设置里面的宽度。在您的示例中,将格式从“|-16-[view]-16-|”更改到“|-16-[视图(288)]-16-|”应该会给你一个很好的结果。 这行得通。在我看来,数字 4 是更好的方法,因为它很简单并且避免了任何幻数(这意味着它支持旋转等)。【参考方案2】:找到了一个适用于您的用例的可行解决方案。见here。
【讨论】:
【参考方案3】:扩展 Patric Schenke 答案的第 4 条;因为scrollView
的内容大小是流动的,所以将内部视图固定到其边缘并不能确定视图的宽度。您的左侧销会起作用,但两者都不会。根据上一级容器计算视图的宽度是要走的路。只要你的self.scrollView
被固定到它的容器中(我称之为containerView
),这行代码就可以完成你想要的。将此行添加到您的 for
循环以获取水平约束:
// Pin view's width to match the scrollView container's width
// -32 constant offset for margins
[containerView addConstraint:
[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:containerView
attribute:NSLayoutAttributeWidth
multiplier:1.0f
constant:-32]];
【讨论】:
【参考方案4】:我找到了一种简单的基于约束的方法来实现这一点(我还没有测试过这个解决方案的脆弱程度):
...@"H:|-16-[view]-16-|"... // (your original constraint)
[self.scrollView addConstraint:
[NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.scrollView
attribute:NSLayoutAttributeCenterX
multiplier:1.0f
constant:0.0f]];
这将view
一直延伸到视图的另一侧。这对于水平滚动但应该垂直滚动的内容可能并不理想。
我意识到这是一年多之后的事了,但对于单维滚动用例来说,它比 patric.schenke 的答案更简单(很好而且更健壮)。
【讨论】:
以上是关于UIView 不遵守 UIScrollView 中的自动布局约束的主要内容,如果未能解决你的问题,请参考以下文章
为啥我在 ScrollView 中的 UIView 不遵守它的高度限制?
自定义 UIView 中的 UIScrollView 不滚动