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
和它的scrollView
( scrollView
)之间的约束是scrollView
的contentSize
,而不是它的frame
。 这可能看起来很混乱,但实际上它非常有用,这意味着您不必调整contentSize
,而是可以自动调整contentSize
以适合您的内容。 技术说明TN2154中描述了此行为。
如果你想定义contentView
大小到屏幕或类似的东西,你必须在contentView
和主视图之间添加一个约束。 无可否认的是,将内容放入滚动视图是不合适的,所以我可能不会build议这样做,但是可以这样做。
为了说明这个概念, contentView
的大小将由其内容驱动,而不是由scrollView
的bounds
来驱动,为你的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
(以及scrollView
的contentSize
)被调整为符合标准页边距的标签。 而且因为我没有指定标签的宽度/高度,所以会根据您放入该标签的文字进行调整。
如果你想让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); }