我在使用自动布局限制时遇到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高度的变化?
到目前为止,我能想到的唯一解决方案是在动画后手动设置ContainerView的高度,这将是ViewA + ViewB + Button高度的总和。但我相信有更好的解决方案?
由于
答案 0 :(得分:58)
我使用纯粹的结构,如下所示
-view
-scrollView
-view A
-view B
-Button
确保按钮(最后一个视图)有一个约束(从底部到超级视图的垂直间距,即滚动视图),在这种情况下,无论您的视图A和视图有什么变化B就是,scrollView的高度会相应改变。
我参考了这个伟大的在线book site。
只需阅读“创建滚动视图”部分,您应该有一个想法。
我遇到类似的问题,我正在创建一个详细视图,并且使用带有Auto布局的Interface Builder非常适合这项任务!
祝你好运!(其他资源:
关于auto layout for scroll view的堆栈溢出讨论。
iOS 6的Release Notes讨论了UIScrollView的自动布局支持。
免费在线iOS book explanation关于滚动视图。这实际上帮助了我很多!
答案 1 :(得分:25)
假设我们有这样的层次结构(Label1是ContentView的子视图; ContentView是ScrollView的子视图,ScrollView是viewcontroller视图的子视图):
ViewController's View
ScrollView
ContentView
Label1
Label2
Label3
ScrollView以与viewcontroller视图相同的正常方式使用autolayout进行约束。
ContentView被固定在scrollview的顶部/左侧/右侧/底部。这意味着你有一些约束使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的高度。
我希望这给某人一个线索,因为我阅读了上面的帖子,仍然无法弄清楚如何正确地使ContentView的宽度和高度限制。我缺少的是将Label3的底部固定在ContentView的底部,否则ContentView怎么会知道它有多高(因为Label3就会浮动,并且没有约束来告诉ContentView它的底部位置是什么)。 / p>
答案 2 :(得分:7)
这是我如何使用容器视图布局纯自动布局UIScrollView的示例。我评论说要更清楚:
容器是标准的UIView,而body是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的大小。
答案 3 :(得分:1)
使用此代码。 ScrollView setContentSize应该在主线程中调用async。
夫特:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
DispatchQueue.main.async {
var contentRect = CGRect.zero
for view in self.scrollView.subviews {
contentRect = contentRect.union(view.frame)
}
self.scrollView.contentSize = contentRect.size
}
}
目标C:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
dispatch_async(dispatch_get_main_queue(), ^ {
CGRect contentRect = CGRectZero;
for(UIView *view in scrollView.subviews)
contentRect = CGRectUnion(contentRect,view.frame);
scrollView.contentSize = contentRect.size;
});
}
答案 4 :(得分:0)
滚动视图每时每刻都应该知道其内容大小。内容大小是从scrollview的子视图中推断出来的。将控制器属性映射到描述子视图高度的xib文件中的约束非常方便。然后在代码(动画块)中,您可以只更改这些约束属性的常量。如果需要更改整个约束,请保留对它的引用,以便稍后可以在父容器中更新它。
答案 5 :(得分:0)
我的滚动视图变体!onPress= {()=> {
this._MyComponent.setNativeProps({text:'my new text'});
}
!高度:
1)将Dynamic
添加到scroll view
。固定所有(顶部,底部,引导,轨迹)约束。
2)将UIView
添加到UIView
。固定所有(顶部,底部,引导,轨迹)约束。这将是你的Scroll View
。你也可以重命名它。
3)控制从Content view
拖动到Content view
- Scroll view
4)向Equal width
添加内容。设置所需的约束。和!在较低的项目中添加底部约束不 UIView
(Greater or equal
)(与大多数人一样)但 >=
!例如,将其设置为Equal
。
在我的情况下,我的内容为20
。我已将UIImageView
连接到代码。如果我将其更改为height
,则滚动显示。一切正常。
对我来说就像一个魅力。有任何问题 - 欢迎提出意见。