带有 UIScrollview 的 iOS 自动布局:为什么滚动视图的内容视图没有填充滚动视图?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16843633/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iOS Autolayout with UIScrollview: Why does content view of scroll view not fill the scroll view?
提问by dragosaur
The following code (called in viewDidLoad) results in a fully red screen. I would expect it to be a fully green screen. Why is it red? And how can I make it all green?
以下代码(在 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]];
回答by Rob
Constraints with scroll views work slightly differently than it does with other views. The constraints between of contentView
and its superview
(the scrollView
) are to the scrollView
's contentSize
, not to its frame
. This might seem confusing, but it is actually quite useful, meaning that you never have to adjust the contentSize
, but rather the contentSize
will automatically adjust to fit your content. This behavior is described in Technical Note TN2154.
滚动视图约束的工作方式与其他视图略有不同。ofcontentView
和它的superview
(the scrollView
)之间的约束是对scrollView
的contentSize
,而不是它的frame
。这可能看起来令人困惑,但它实际上非常有用,这意味着您永远不必调整contentSize
,而是contentSize
会自动调整以适合您的内容。此行为在技术说明 TN2154 中进行了描述。
If you want to define the contentView
size to the screen or something like that, you'd have to add a constraint between the contentView
and the main view, for example. That's, admittedly, antithetical to putting content into the scrollview, so I probably wouldn't advise that, but it can be done.
例如,如果你想定义contentView
屏幕的大小或类似的东西,你必须contentView
在主视图和主视图之间添加一个约束。诚然,这与将内容放入滚动视图相反,所以我可能不建议这样做,但可以做到。
To illustrate this concept, that the size of contentView
will be driven by its content, not by the bounds
of the scrollView
, add a label to your contentView
:
为了说明这个概念,即规模contentView
将由其内容来驱动,而不是由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]];
Now you'll see that the contentView
(and, therefore, the contentSize
of the scrollView
) are adjusted to fit the label with standard margins. And because I didn't specify the width/height of the label, that will adjust based upon the text you put into that label.
现在,您将看到 的contentView
(以及contentSize
的scrollView
)已调整为适合具有标准边距的标签。而且因为我没有指定标签的宽度/高度,这将根据您放入该标签的文本进行调整。
If you want the contentView
to also adjust to the width of the main view, you could do redefine your viewDict
like so, and then add these additional constraints (in addition to all the others, above):
如果您还希望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]];
There is a known issue (bug?)with multiline labels in scrollviews, that if you want it to resize according to the amount of text, you have to do some sleight of hand, such as:
滚动视图中的多行标签存在一个已知问题(错误?),如果您希望它根据文本量调整大小,则必须采取一些技巧,例如:
dispatch_async(dispatch_get_main_queue(), ^{
randomLabel.preferredMaxLayoutWidth = self.view.bounds.size.width;
});
回答by Hlung
I tried Rob's answer looks fine at first. BUT!if you also enabled zooming, this Autolayout code will get in the way. It keeps resizing the contentView when zooms.That is, if I zoomed in (zoomScale > 1), I won't be able to scroll the the parts outside the screen.
我试过 Rob 的答案起初看起来不错。但!如果您还启用了zooming,则此 Autolayout 代码将成为障碍。它在缩放时不断调整 contentView 的大小。也就是说,如果我放大(zoomScale > 1),我将无法滚动屏幕外的部分。
After days of fighting with Autolayout, sadly I couldn't find any solution. In the end, it doesn't even matter (wat? ok, sorry). In the end, I just remove Autolayout on contentView (use a fixed size contentView), and then in layoutSubviews, I adjust theself.scrollView.contentInset
. (I'm using Xcode5, iOS 7)
经过几天与 Autolayout 的斗争,遗憾的是我找不到任何解决方案。最后,这甚至无关紧要(wat?好的,抱歉)。最后,我只是删除了 contentView 上的 Autolayout(使用固定大小的 contentView),然后在 layoutSubviews 中,我调整了self.scrollView.contentInset
. (我使用的是 Xcode5,iOS 7)
I know this is not a direct solution to this question. But I just want to point out an easy workaround. It works perfectly for centering a fixed-size contentView in a scrollView, with just 2 lines of code! Hope it may help someone ;)
我知道这不是这个问题的直接解决方案。但我只想指出一个简单的解决方法。它非常适合在滚动视图中居中固定大小的内容视图,只需 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);
}
回答by Afzal Siddiqui
In general, Auto Layout considers the top, left, bottom, and right edges of a view to be the visible edges. That is, if you pin a view to the left edge of its superview, you're really pinning it to the minimum x-value of the superview's bounds. Changing the bounds origin of the superview does not change the position of the view.
通常,自动布局将视图的顶部、左侧、底部和右侧边缘视为可见边缘。也就是说,如果您将视图固定到其父视图的左边缘,您实际上是将其固定到父视图边界的最小 x 值。改变超级视图的边界原点不会改变视图的位置。
The UIScrollView class scrolls its content by changing the origin of its bounds. To make this work with Auto Layout, the top, left, bottom, and right edges within a scroll view now mean the edges of its content view.
UIScrollView 类通过更改其边界的原点来滚动其内容。为了使其与自动布局一起工作,滚动视图中的顶部、左侧、底部和右侧边缘现在表示其内容视图的边缘。
The constraints on the subviews of the scroll view must result in a size to fill, which is then interpreted as the content size of the scroll view. (This should not be confused with the intrinsicContentSize method used for Auto Layout.) To size the scroll view's frame with Auto Layout, constraints must either be explicit regarding the width and height of the scroll view, or the edges of the scroll view must be tied to views outside of its subtree.
对滚动视图子视图的约束必须导致要填充的大小,然后将其解释为滚动视图的内容大小。(这不应与用于自动布局的内在内容大小方法混淆。)要使用自动布局调整滚动视图框架的大小,必须明确约束滚动视图的宽度和高度,或者滚动视图的边缘必须是与其子树之外的视图相关联。
Note that you can make a subview of the scroll view appear to float (not scroll) over the other scrolling content by creating constraints between the view and a view outside the scroll view's subtree, such as the scroll view's superview.
请注意,您可以通过在视图和滚动视图子树外部的视图(例如滚动视图的超级视图)之间创建约束,使滚动视图的子视图看起来浮动(而不是滚动)在其他滚动内容上。
Here are two examples of how to configure the scroll view, first the mixed approach, and then the pure approach
下面是如何配置滚动视图的两个示例,首先是混合方式,然后是纯方式