具有自动布局约束的UIScrollView:自动内容大小计算

时间:2015-08-04 20:45:28

标签: ios objective-c uiscrollview autolayout ios-autolayout

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

- ScrollView (leading, trailing, bottom and top spaces to Superview)
-- ContainerView (leading, trailing, bottom and top spaces to ScrollView)
--- Button 1 (full width, **top space to ContainerView**)
--- Button 2 (full width, below Button 1)
--- Button n (full width, below Button n-1, **bottom space to ContainerView**)

enter image description here

我想要一个简单的scrollabel按钮列表。这是我的代码:

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self.view setBackgroundColor:[UIColor redColor]];
    [self.contentView setBackgroundColor:[UIColor yellowColor]];

    UIView *lastView= self.contentView; // use for top constraint

    NSInteger topBottomMargin= 10, leftRightMargin= 16;
    for (int i=0; i<10; i++) {
        UIButton *button= [UIButton buttonWithType:UIButtonTypeSystem];
        button.translatesAutoresizingMaskIntoConstraints= NO;
        [button setTitle:[NSString stringWithFormat:@"Button %d", i] forState:UIControlStateNormal];

        [self.contentView addSubview:button];

        // add constraints
        // top
        [self.contentView addConstraint:[NSLayoutConstraint
                                         constraintWithItem:lastView
                                         attribute:NSLayoutAttributeBottom
                                         relatedBy:NSLayoutRelationGreaterThanOrEqual
                                         toItem:button
                                         attribute:NSLayoutAttributeTop
                                         multiplier:1.0 constant:-topBottomMargin]];
        // left
        [self.contentView addConstraint:[NSLayoutConstraint
                                         constraintWithItem:self.contentView
                                         attribute:NSLayoutAttributeLeading
                                         relatedBy:NSLayoutRelationEqual
                                         toItem:button
                                         attribute:NSLayoutAttributeLeading
                                         multiplier:1.0 constant:-leftRightMargin]];
        // right
        [self.contentView addConstraint:[NSLayoutConstraint
                                         constraintWithItem:self.contentView
                                         attribute:NSLayoutAttributeTrailing
                                         relatedBy:NSLayoutRelationEqual
                                         toItem:button
                                         attribute:NSLayoutAttributeTrailing
                                         multiplier:1.0 constant:leftRightMargin]];

        lastView= button;
    }
    // bottom
    [self.contentView addConstraint:[NSLayoutConstraint
                                     constraintWithItem:self.contentView
                                     attribute:NSLayoutAttributeBottom
                                     relatedBy:NSLayoutRelationEqual
                                     toItem:lastView
                                     attribute:NSLayoutAttributeBottom
                                     multiplier:1.0 constant:topBottomMargin]];    
}

看来contentView的高度为0!但是它的顶部和底部都有限制。它应该是这样的:

enter image description here

但是我的代码就是这样的。任何帮助都会很棒。

enter image description here

4 个答案:

答案 0 :(得分:1)

您可以向容器视图添加约束以将视图滚动为Equal height&amp;宽度相等。此外,当您向按钮添加约束时,不要忘记向按钮添加底部约束,因为它将决定滚动视图的结束(内容大小)。

答案 1 :(得分:0)

由于您在contentView上使用自动布局约束,因此viewDidLoad方法中的高度(帧)将为零。您应该将代码移到viewDidLayoutSubviews方法中并尝试在那里添加按钮。

你应该得到contentView的高度。如果有效,请告诉我。希望这会有所帮助。

请参阅此问题以供参考:iOS AutoLayout - get frame size width

答案 2 :(得分:0)

我认为我们不能将自动布局直接添加到ScrollView内的ContainerView,其内部大小为默认值,因此我以编程方式将ContainerView添加为子视图:

- (void)viewDidLoad{
    [super viewDidLoad];

    self.contentView = [[UIView alloc] initWithFrame:CGRectZero];
    [self.scrollView addSubview:self.contentView];

    //Then add your button here as normal.
    //...
}

Gurtej Singh是对的,我们必须更新viewDidLayoutSubviews中的框架:

- (void)viewDidLayoutSubviews
 {
     [super viewDidLayoutSubviews];
    //Don't for get to update your self.scrollView.contentSize if you want to able to scroll
    //...

    //Update your contentView frame based on scrollview frame and self.scrollView.contentSize.
     self.contentView.frame = self.scrollView.bounds or ....;
 }

我只想提供帮助,这可能不是一个好的解决方案,但它对我有用。

答案 3 :(得分:0)

我找到了我正在寻找的解决方案here

[super viewDidLoad];
UIScrollView* sv = [UIScrollView new];
sv.backgroundColor = [UIColor whiteColor];
sv.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:sv];
[self.view addConstraints:
 [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[sv]|"
                                         options:0 metrics:nil
                                           views:@{@"sv":sv}]];
[self.view addConstraints:
 [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[sv]|"
                                         options:0 metrics:nil
                                           views:@{@"sv":sv}]];
UILabel* previousLab = nil;
for (int i=0; i<30; i++) {
    UILabel* lab = [UILabel new];
    lab.translatesAutoresizingMaskIntoConstraints = NO;
    lab.text = [NSString stringWithFormat:@"This is label %i", i+1];
    [sv addSubview:lab];
    [sv addConstraints:
     [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[lab]"
                                             options:0 metrics:nil
                                               views:@{@"lab":lab}]];
    if (!previousLab) { // first one, pin to top
        [sv addConstraints:
         [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(10)-[lab]"
                                                 options:0 metrics:nil
                                                   views:@{@"lab":lab}]];
    } else { // all others, pin to previous
        [sv addConstraints:
         [NSLayoutConstraint
          constraintsWithVisualFormat:@"V:[prev]-(10)-[lab]"
                                  options:0 metrics:nil
                                    views:@{@"lab":lab, @"prev":previousLab}]];
    }
    previousLab = lab;
}
// last one, pin to bottom and right, this dictates content size height
[sv addConstraints:
 [NSLayoutConstraint constraintsWithVisualFormat:@"V:[lab]-(10)-|"
                                         options:0 metrics:nil
                                           views:@{@"lab":previousLab}]];
[sv addConstraints:
 [NSLayoutConstraint constraintsWithVisualFormat:@"H:[lab]-(10)-|"
                                         options:0 metrics:nil
                                           views:@{@"lab":previousLab}]];
// look, Ma, no contentSize!