使用UIScrollview的iOS Autolayout:为什么滚动视图的内容视图不会填充滚动视图?

时间:2013-05-30 18:42:12

标签: ios ios6 uiscrollview autolayout

以下代码(在viewDidLoad中调用)会产生一个完全红色的屏幕。我希望它是一个完全绿色的屏幕。它为什么是红色的?我怎么能把它全部变成绿色呢?

UIScrollView* scrollView = [UIScrollView new];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
scrollView.backgroundColor = [UIColor redColor];
[self.view addSubview:scrollView];

UIView* contentView = [UIView new];
contentView.translatesAutoresizingMaskIntoConstraints = NO;
contentView.backgroundColor = [UIColor greenColor];
[scrollView addSubview:contentView];

NSDictionary* viewDict = NSDictionaryOfVariableBindings(scrollView,contentView);

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics:0 views:viewDict]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics:0 views:viewDict]];

[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options:0 metrics:0 views:viewDict]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|" options:0 metrics:0 views:viewDict]];

3 个答案:

答案 0 :(得分:70)

滚动视图的约束与其他视图的约束略有不同。 contentView及其superviewscrollView)之间的约束是scrollView的{​​{1}},而不是contentSize。这可能看起来令人困惑,但它实际上非常有用,这意味着您永远不必调整frame,而contentSize会自动调整以适合您的内容。 Technical Note TN2154中描述了此行为。

如果要在屏幕上定义contentSize大小或类似大小,则必须在contentView和主视图之间添加约束。不可否认,这与将内容放入滚动视图是对立的,所以我可能不会建议,但可以这样做。


为了说明这一概念,contentView的大小将由其内容驱动,而不是由contentView的{​​{1}}驱动,请为bounds添加标签:

scrollView

现在,您会看到contentView(以及UIScrollView* scrollView = [UIScrollView new]; scrollView.translatesAutoresizingMaskIntoConstraints = NO; scrollView.backgroundColor = [UIColor redColor]; [self.view addSubview:scrollView]; UIView* contentView = [UIView new]; contentView.translatesAutoresizingMaskIntoConstraints = NO; contentView.backgroundColor = [UIColor greenColor]; [scrollView addSubview:contentView]; UILabel *randomLabel = [[UILabel alloc] init]; randomLabel.text = @"this is a test"; randomLabel.translatesAutoresizingMaskIntoConstraints = NO; randomLabel.backgroundColor = [UIColor clearColor]; [contentView addSubview:randomLabel]; NSDictionary* viewDict = NSDictionaryOfVariableBindings(scrollView, contentView, randomLabel); [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics:0 views:viewDict]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics:0 views:viewDict]]; [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options:0 metrics:0 views:viewDict]]; [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|" options:0 metrics:0 views:viewDict]]; [contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[randomLabel]-|" options:0 metrics:0 views:viewDict]]; [contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[randomLabel]-|" options:0 metrics:0 views:viewDict]]; 的{​​{1}})已调整为符合标准边距的标签。因为我没有指定标签的宽度/高度,所以会根据您放入该标签的文字进行调整。


如果您希望contentView也调整到主视图的宽度,您可以像这样重新定义contentSize,然后添加这些附加约束(除了所有其他约束之外,以上):

scrollView

滚动视图中有一个带有多行标签的known issue (bug?),如果您希望根据文本的数量调整大小,则需要做一些操作,例如:

contentView

答案 1 :(得分:1)

我试过Rob的答案一开始看起来很好。 但是!如果您还启用了缩放,则此Autolayout代码将受到阻碍。 在缩放时不断调整contentView的大小。也就是说,如果我放大(zoomScale> 1),我将无法滚动屏幕外的部分。

经过几天与Autolayout的斗争,遗憾的是我找不到任何解决方案。最后,它甚至不重要(扫管笏?好吧,对不起)。最后,我只是在contentView上删除了Autolayout(使用固定大小的contentView),然后在layoutSubviews中调整 self.scrollView.contentInset。 (我正在使用Xcode5,iOS 7)

我知道这不是这个问题的直接解决方案。但我只想指出一个简单的解决方法。它完美地适用于在scrollView中居中固定大小的contentView,只需2行代码!希望它可以帮助某人;)

- (void)layoutSubviews {
    [super layoutSubviews];

    // move contentView to center of scrollView by changing contentInset,
    // because I CANNOT set this with AUTOLAYOUT!!!
    CGFloat topInset = (self.frame.size.height - self.contentView.frame.size.height)/2;
    self.scrollView.contentInset = UIEdgeInsetsMake(topInset, 0, 0, 0);
}

答案 2 :(得分:-1)

通常,“自动布局”会将视图的顶部,左侧,底部和右侧边缘视为可见边缘。也就是说,如果将视图固定到其超视图的左边缘,则实际上将其固定到超视图边界的最小x值。更改超级视图的边界原点不会更改视图的位置。

UIScrollView类通过更改其边界的原点来滚动其内容。要使其与“自动布局”一起使用,滚动视图中的顶部,左侧,底部和右侧边缘现在表示其内容视图的边缘。

滚动视图子视图的约束必须导致填充大小,然后将其解释为滚动视图的内容大小。 (这不应与用于自动布局的intrinsicContentSize方法混淆。)要使用自动布局调整滚动视图的框架大小,约束必须明确关于滚动视图的宽度和高度,或者滚动视图的边缘必须是与其子树之外的视图相关联。

请注意,您可以通过在视图和滚动视图的子树外部的视图(例如滚动视图的超级视图)之间创建约束,使滚动视图的子视图显示为浮动(不滚动)在其他滚动内容上。

以下是两个如何配置滚动​​视图的示例,首先是混合方法,然后是纯方法