UIView不遵守UIScrollView中的autolayout约束

时间:2013-07-21 13:48:04

标签: ios cocoa-touch uiview autolayout

我正在向UIScrollView添加一个UIView并对其进行约束,使其填充水平空间,除了一些边距。我的视觉约束看起来像这样:

@"|-16-[theLineView]-16-|"

我已将视图设为一个像素高,因此它将显示为一条线,并将其放在两个文本标签之间:

@"V:[someOtherStuff]-[aTextLabel]-[theLineView]-[anotherLabel]"

但是,我发现线条的宽度只会扩展到它上面/下面最长标签的宽度。

为什么会这样?

P.S我读过这个http://developer.apple.com/library/ios/#technotes/tn2154/_index.html

enter image description here

代码

以下是来自测试项目的整个视图控制器代码,该代码在iPad sim上显示此问题。

- (void)viewDidLoad

{     [super 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}]];

}

4 个答案:

答案 0 :(得分:7)

UIScrollView会自动缩小以适应其中的视图。你需要在某个地方设置宽度。

推荐策略:

  1. 使用约束(前导,尾随,顶部,底部)在其父视图中完全固定scrollview。
  2. 在UIScrollView中创建一个UIView,并将您需要的所有内容放入其中。
  3. 设置约束,以便UIView充当内容视图(这意味着它足够大以包含所有元素)。使用内在的内容大小,抗收缩性和元素的链接有很多约束。生成的布局必须定义明确且唯一(这意味着如果要将所有约束移除到外部,布局仍然有效)。
  4. 将UIView的边界与他们的超级视图(这是UIScrollView的实际内容视图,而不是UIScrollView!)连接起来。
  5. 如果在interface-builder中执行此操作(可能),则每次触摸该场景中的某些内容时都需要重新检查约束。触摸我的意思是“选择”不仅“修改”。

答案 1 :(得分:2)

找到一个适用于您的用例的工作解决方案。请参阅here

答案 2 :(得分:2)

扩大Patric Sc​​henke答案的第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]];

答案 3 :(得分:0)

我找到了一种简单的基于约束的方法来实现这一目标(我没有测试过这种解决方案的脆弱程度):

...@"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的答案(它更好且更强大)更简单。