自动布局具有dynamic高度子视图的UIScrollView

我遇到了使用自动布局约束的UIScrollView问题。 我有以下视图层次结构,通过IB设置约束:

- ScrollView (leading, trailing, bottom and top spaces to superview) -- ContainerView (leading, trailing, bottom and top spaces to superview) --- ViewA (full width, top of superview) --- ViewB (full width, below ViewA) --- Button (full width, below ViewB) 

ViewA和ViewB的初始高度为200点,但点击它可以垂直消耗400点的高度。 ViewA和ViewB通过更新高度约束(从200到400)进行扩展。 这里是相应的片段:

 if(self.contentVisible) { heightConstraint.constant -= ContentHeight; // + additional View's internal constraints update to hide additional content self.contentVisible = NO; } else { heightConstraint.constant += ContentHeight; // + additional View's internal constraints update to show additional content self.contentVisible = YES; } [self.view setNeedsUpdateConstraints]; [UIView animateWithDuration:.25f animations:^{ [self.view layoutIfNeeded]; }]; 

我的问题是,如果两个视图都展开,我需要能够滚动查看整个内容,现在滚动不起作用。 我如何设法使用约束来更新滚动视图以反映ViewA和ViewB高度的变化?

到目前为止,我唯一能想到的解决scheme是在animation之后手动设置ContainerView的高度,这将是ViewA + ViewB + Button的高度的总和。 但是我相信有更好的解决办法?

谢谢

我使用如下的纯结构

 -view -scrollView -view A -view B -Button 

确保button( 最后一个视图 )有一个约束(垂直间距从底部到超视图,这是滚动视图),在这种情况下,无论视图A和视图B会发生什么变化,scrollView的高度都会相应地改变。

我参考这个伟大的在线书籍网站 。

只要阅读“创build滚动视图”部分,你应该有一个想法。

我有类似的问题,我正在创build一个详细视图和使用界面生成器与自动布局是这样一个很好的任务!

祝你好运!

(其他资源:

关于滚动视图的自动布局的堆栈溢出讨论。

iOS 6有一个关于UIScrollView自动布局支持的发行说明 。

有关滚动视图的免费在线iOS书籍解释 。 这实际上帮了我很多!

假设我们有这样的层次(Label1是ContentView的子视图; ContentView是ScrollView的子视图,ScrollView是viewcontroller视图的子视图):

ViewController's View ScrollView ContentView Label1 Label2 Label3

ScrollView受限于自动布局,正常情况下视图控制器的视图。

ContentView是固定顶部/左/右/底部滚动视图。 这意味着您有限制,使得ContentView的顶部/底部/前端/尾部边缘被限制为与ScrollView上的边缘相同。 这是一个关键:这些约束是针对ScrollView的contentSize,而不是viewcontroller的视图中显示的帧大小。 所以它不会告诉ContentView与显示的ScrollView框架的帧大小相同,而是告诉Scrollview ContentView是它的内容,所以如果contentview大于ScrollView框架,那么你会滚动,就像设置scrollView.contentSize更大比scrollView.frame使内容可滚动。

这里还有另一个关键:现在你必须在ContentView,Label1-3和除了Scrollview以外的ContentView之间有足够的约束,以便能够从这些约束中找出它的宽度和高度。

例如,如果你想要一个垂直滚动的标签集合,你设置一个约束来使ContentView的宽度等于ViewController视图的宽度,这将处理宽度。 为了照顾高度,将Label1顶部固定到ContentView顶部,将Label2顶部固定到Label1底部,将Label3顶部固定到Label2底部,最后(并且重要)将Label3的底部固定到ContentView的底部。 现在它有足够的信息来计算ContentView的高度。

我希望这给了一个线索,当我读通过上述post,仍然不知道如何正确地使ContentView的宽度和高度约束。 我错过的是将Label3的底部固定到ContentView的底部,否则ContentView怎么知道它是多么高(因为Label3只是浮动的,并且不会告诉ContentView它位于底部y的位置)。

这是一个例子,我已经展示了一个带有容器视图的纯自动布局UIScrollView。 我已经评论说清楚了:

容器是一个标准的UIView和正文是一个UITextView

 - (void)viewDidLoad { [super viewDidLoad]; //add scrollview [self.view addSubview:self.scrollView]; //add container view [self.scrollView addSubview:self.container]; //body as subview of container (body size is undetermined) [self.container addSubview:self.body]; NSDictionary *views = @{@"scrollView" : self.scrollView, @"container" : self.container, @"body" : self.body}; NSDictionary *metrics = @{@"margin" : @(100)}; //constrain scrollview to superview, pin all edges [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:kNilOptions metrics:metrics views:views]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:kNilOptions metrics:metrics views:views]]; //pin all edges of the container view to the scrollview (i've given it a horizonal margin as well for my purposes) [self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[container]|" options:kNilOptions metrics:metrics views:views]]; [self.scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-margin-[container]-margin-|" options:kNilOptions metrics:metrics views:views]]; //the container view must have a defined width OR height, here i am constraining it to the frame size of the scrollview, not its bounds //the calculation for constant is so that it's the width of the scrollview minus the margin * 2 [self.scrollView addConstraint:[NSLayoutConstraint constraintWithItem:self.container attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.scrollView attribute:NSLayoutAttributeWidth multiplier:1.0f constant:-([metrics[@"margin"] floatValue] * 2)]]; //now as the body grows vertically it will force the container to grow because it's trailing edge is pinned to the container's bottom edge //it won't grow the width because the container's width is constrained to the scrollview's frame width [self.container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[body]|" options:kNilOptions metrics:metrics views:views]]; [self.container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[body]|" options:kNilOptions metrics:metrics views:views]]; } 

在我的例子中,“body”是一个UITextView,但它可能是其他任何东西。 如果你碰巧使用UITextView,那么请注意,为了垂直增长它必须有一个高度约束,在viewDidLayoutSubviews中设置。 所以在viewDidLoad中添加下面的约束并保存对它的引用:

 self.bodyHeightConstraint = [NSLayoutConstraint constraintWithItem:self.body attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:nil multiplier:1.0f constant:100.0f]; [self.container addConstraint:self.bodyHeightConstraint]; 

然后在viewDidLayoutSubviews中计算高度并更新约束的常量:

 - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; [self.bodyHeightConstraint setConstant:[self.body sizeThatFits:CGSizeMake(self.container.width, CGFLOAT_MAX)].height]; [self.view layoutIfNeeded]; } 

第二个布局过程需要调整UITextView的大小。

每次滚动视图都应该知道它的内容大小。 内容大小从滚动视图的子视图中推断出来。 将控制器属性映射到描述子视图高度的xib文件中的约束是非常方便的。 然后在代码中(一个animation块),你可以改变这些约束属性的常量。 如果您需要更改整个约束,请保留对其的引用,以便稍后在父容器中对其进行更新。

使用这个代码。 ScrollView的setContentSize应该在主线程中调用async。

 - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; dispatch_async(dispatch_get_main_queue(), ^ { CGRect contentRect = CGRectZero; for (UIView *view in scrollView.subviews) if (!view.hidden) contentRect = CGRectUnion(contentRect, view.frame); contentRect.size.height=contentRect.size.height; scrollView.contentSize = contentRect.size; }); } 

我与滚动视图的变种! Dynamic ! 高度:

1)添加scroll view到你的UIView 。 固定所有(顶部,底部,引导,尾迹)约束。

2)添加UIView Scroll View 。 固定所有(顶部,底部,引导,尾迹)约束。 这将是你的Content view 。 您也可以重命名它。

3)控制从Content view拖动Scroll viewEqual width

4)添加内容到你的UIView 。 设置所需的约束。 和! 在较低的项目添加底部约束NOT Greater or equal>= )(像大多数人谈话), Equal ! 例如,将其设置为20

在我的情况下,我有UIImageView的内容。 我已经把它的height连接到代码。 如果我将其更改为1000 ,滚动是可见的。 和所有的作品。

对我来说就像一个魅力。 任何问题 – 欢迎评论。