Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use UIScrollView with AutoLayout (iOS6)?

I am trying to build a view that will have several different controls, but I want the view to only scroll in the vertical direction. I'm using auto-layout so I don't want to have to specify the size manually (I know I can do that, but from what I understand according to the release notes on UIScrollView you should not have to).

So if I create a simple view controller (with no .xib file) and simply add the following to the init method I'd expect that my labels would wrap (which they do) and that my view would scroll vertically, however, this is not the case:

- (id)init {
    self = [super init];
    if (self) {

        UIScrollView *_scrollView = [UIScrollView new];
        [_scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];

        UILabel *label1 = [UILabel new];
        UILabel *label2 = [UILabel new];

        [label1 setTranslatesAutoresizingMaskIntoConstraints:NO];
        [label2 setTranslatesAutoresizingMaskIntoConstraints:NO];

        [label1 setNumberOfLines:0];
        [label2 setNumberOfLines:0];

        [label1 setPreferredMaxLayoutWidth:240];
        [label2 setPreferredMaxLayoutWidth:240];

        NSString *sampleText = @"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";
        [label1 setText:sampleText];
        [label2 setText:sampleText];

        [self.view addSubview:_scrollView];
        [_scrollView addSubview:label1];
        [_scrollView addSubview:label2];

        NSArray *constraints;
        constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_scrollView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_scrollView)];
        [self.view addConstraints:constraints];

        constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_scrollView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_scrollView)];
        [self.view addConstraints:constraints];

        constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[label1]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(label1)];
        [_scrollView addConstraints:constraints];

        constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[label2]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(label2)];
        [_scrollView addConstraints:constraints];

        constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[label1]-[label2]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(label1, label2)];
        [_scrollView addConstraints:constraints];
    }

    return self;
}

There are several results from this code that I think are odd. If you log the scrollviewheight in the viewDidLayoutSubviews method (after the super call), which is where all constraints should be applied, then the height is reporting 0. What's also strange is that the width is reporting a different number than I would expect. I would expect it to report the width of the superview due to the very first constraint (I even tried forcing the width inside that constraint with a priority that is supposedly required but it still didn't work).

As I understand it, the UIScrollView's content size should be set by the intrinsic sizes of its content but that doesn't seem to be happening.

So, does anyone know what is missing?

like image 472
Adam Avatar asked Dec 12 '12 21:12

Adam


1 Answers

I had contacted Apple's support to get an answer on my question. The problem with the code is that the objects contained within the UIScrollView must be pinned to both the top and bottom vertically for it to determine its intrinsic content size. So the following line of code

constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[label1]-[label2]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(label1, label2)];
[_scrollView addConstraints:constraints];

Should be changed to:

constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[label1]-[label2]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(label1, label2)];
[_scrollView addConstraints:constraints];

They also pointed out that I was using the "new" keyword on several objects where the basic "init" is not the designated initializer. While that had nothing to do with my specific problem they did point out that you should avoid doing that as your object could be in an invalid state.

like image 121
Adam Avatar answered Sep 30 '22 14:09

Adam