iOS自动化与UIScrollview:为什么滚动视图的内容视图不能填充滚动视图?

以下代码(在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]]; 

滚动视图的约束与其他视图的约束不同。 contentView和它的scrollViewscrollView )之间的约束是scrollViewcontentSize ,而不是它的frame 。 这可能看起来很混乱,但实际上它非常有用,这意味着您不必调整contentSize ,而是可以自动调整contentSize以适合您的内容。 技术说明TN2154中描述了此行为。

如果你想定义contentView大小到屏幕或类似的东西,你必须在contentView和主视图之间添加一个约束。 无可否认的是,将内容放入滚动视图是不合适的,所以我可能不会build议这样做,但是可以这样做。


为了说明这个概念, contentView的大小将由其内容驱动,而不是由scrollViewbounds来驱动,为你的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]]; 

现在您将看到contentView (以及scrollViewcontentSize )被调整为符合标准页边距的标签。 而且因为我没有指定标签的宽度/高度,所以会根据您放入该标签的文字进行调整。


如果你想让contentView也适应主视图的宽度,你可以像这样重新定义你的viewDict ,然后添加这些额外的约束(除了上面的所有其他约束):

 UIView *mainView = self.view; NSDictionary* viewDict = NSDictionaryOfVariableBindings(scrollView, contentView, randomLabel, mainView); [mainView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[contentView(==mainView)]" options:0 metrics:0 views:viewDict]]; 

在滚动视图中有一个已知的问题(bug?)与多行标签,如果你想要根据文本的大小resize,你必须做一些巧手,例如:

 dispatch_async(dispatch_get_main_queue(), ^{ randomLabel.preferredMaxLayoutWidth = self.view.bounds.size.width; }); 

我试过Rob的答案看起来很好。 但! 如果你还启用了缩放function ,这个Autolayout代码将会阻碍你。 它在放大时不断调整contentView的大小。 也就是说,如果我放大(zoomScale> 1),我将无法滚动屏幕之外的部分。

经过与Autolayout战斗的日子,可惜我找不到任何解决办法。 最后,甚至没有关系(wat?ok,对不起)。 最后, 我只是删除contentView的Autolayout(使用固定大小的contentView),然后在layoutSubviews中,我调整 self.scrollView.contentInset 。 (我正在使用Xcode5,iOS 7)

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

 - (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); }