用动态的高度子视图自动布局的UIScrollView

问题描述 投票:40回答:6

我在使用的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 +按钮的高度之和的高度。但我相信有一个更好的解决办法?

谢谢

ios objective-c uiscrollview autolayout
6个回答
58
投票

我用纯结构类似如下

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

确认按钮(最后一页)有一个约束(从底部到上海华盈,这是滚动型垂直间距),在这种情况下,无论你的观点A和视图B将是什么样的变化,滚动视图的高度也随之改变。

我引用这个伟大的在线book site

刚看完“创建滚动视图”一节中,你应该有一个想法。

我有我创建一个详细视图和使用界面生成器与自动布局就是这样一个非常适合的任务类似的问题!

祝好运!

(其他资源:

有关auto layout for scroll view堆栈溢出讨论。

iOS 6中有Release Notes在谈论UIScrollView的自动布局支持。

关于滚动视图免费在线iOS book explanation。这实际上帮了我很多!


25
投票

比方说,我们有这样的层次结构(Label1的是内容查看的子视图;内容查看是滚动型的子视图,滚动型是视图控制器的视图的subiview):

ViewController's View ScrollView ContentView Label1 Label2 Label3

滚动型在正常方式到ViewController的看法与约束自动版式。

内容查看被钉顶部/左/右/底部滚动型。这意味着您可以约束使内容查看的上/下/前/后缘限制等于在滚动型相同的边缘。这里是一个键:这些约束是用于滚动型的contentSize,而不是它的帧大小如在视图控制器的视图中示出。因此,这不是讲内容查看为帧大小显示的滚动型框架一样,这是相当告诉滚动视图的内容查看是它的内容,因此,如果内容查看比滚动型框架,那么你得到滚动,就像设置scrollView.contentSize大而变大比scrollView.frame使得内容滚动。

这里是另一个关键:现在你得有内容查看,Label1-3,和别的之间有足够的约束,除了滚动视图的内容查看,以便能够从这些约束弄清楚它的宽度和高度。

因此,举例来说,如果你想有一个垂直滚动组标签,你设定一个约束,使内容查看宽度等于视图控制器视图的宽度,即采用宽度的照顾。为了照顾的高度,PIN Label1的顶部内容查看顶部,Label2的顶部LABEL1底部,LABEL3顶部LABEL2底部,最后(和重要的)脚LABEL3的底部内容查看的底部。现在,它有足够的信息来计算内容查看的高度。

我希望这给别人一个线索,当我在上面的帖子阅读,仍然无法弄清楚如何使内容查看的宽度和高度的限制正常。我错过了什么是钉扎LABEL3的底部到内容查看的底部,否则怎么可能内容查看知道它有多高(如LABEL3只想然后是轻飘飘的,就没有约束告诉内容查看它的底部y位置时)。


7
投票

这是我已经如何布局与容器视图纯自动布局的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]];
}

在我的例子“身体”是一个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。


1
投票

使用此代码。滚动型setContentSize应该被称为在主线程异步。

迅速:

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

0
投票

在每一个时刻滚动视图应该知道其内容的大小。内容大小从滚动视图的子视图推断。这是非常方便的控制器属性映射到XIB文件描述所述子视图的高度的限制。然后在代码(动画块),你可以改变这些约束性的常数。如果您需要改变整个约束,保持对它的引用,这样就可以在后面的父容器更新。


0
投票

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

1)添加scroll viewUIView。所有引脚(顶部,底部,铅,TRAIL)的约束。

2)添加到UIView Scroll View。所有引脚(顶部,底部,铅,TRAIL)的约束。这将是你Content view。您也可以将其重命名。

3)控制从拖动到Content view Scroll view - Equal width

4)将内容添加到您的UIView。设置必要的限制。和!在较低的项目添加底部约束NOT Greater or equal>=)(最喜欢的人谈话)但Equal!将它设置为20例如。

在我的情况我有UIImageView内容。我已连接它的height代码。如果我改变它喜欢1000,滚动是可见的。和所有的工作。

作品对我来说就像魅力。如有任何疑问 - 欢迎评论。

© www.soinside.com 2019 - 2024. All rights reserved.