简体   繁体   中英

Auto Layout + UIScrollView and single subview

Just playing around with Auto Layout and UIScrollView. What am I missing here? This displays a blue scrollView at the bottom of the screen but I cannot see the contentView. The view debugger has nothing to say for it either. Any ideas?

//
//  ViewController.m
//  Fit
//
//  Created by Adam Dahan on 2015-03-13.
//  Copyright (c) 2015 Adam Dahan. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()
{
    UIScrollView *scrollView;
    UIView *contentView;
}
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self createViews];
    [self constrainScrollView];
    [self constrainContentView];
}

- (void)createViews
{
#pragma Initialize a scrollView
    scrollView = [[UIScrollView alloc] initWithFrame:CGRectZero];
    scrollView.translatesAutoresizingMaskIntoConstraints = NO;
    scrollView.backgroundColor = [UIColor blueColor];
    scrollView.showsHorizontalScrollIndicator = NO;
    scrollView.showsVerticalScrollIndicator = NO;
    [self.view addSubview:scrollView];

#pragma Initialize a contentView for the scrollView
    contentView = [[UIView alloc] initWithFrame:CGRectZero];
    contentView.backgroundColor = [UIColor redColor];
    contentView.translatesAutoresizingMaskIntoConstraints = NO;
    [scrollView addSubview:contentView];
}

- (void)constrainScrollView
{

#pragma scrollView vertical constraints
    NSArray *cns = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[scrollView(40)]|"
                                                       options:0
                                                       metrics:nil
                                                                views:NSDictionaryOfVariableBindings(scrollView)];
    [self.view addConstraints:cns];

#pragma scrollView horizontal constraints
    cns = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|"
                                              options:0
                                              metrics:nil
                                                views:NSDictionaryOfVariableBindings(scrollView)];
    [self.view addConstraints:cns];
}

- (void)constrainContentView
{

#pragma contentView vertical constraints
    NSArray *cns = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|"
                                              options:0
                                              metrics:nil
                                                views:NSDictionaryOfVariableBindings(scrollView, contentView)];
    [scrollView addConstraints:cns];

#pragma contentView horizontal constraints
    cns = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|"
                                              options:0
                                              metrics:nil
                                                views:NSDictionaryOfVariableBindings(scrollView, contentView)];
    [scrollView addConstraints:cns];
}

@end

You really should check out Technical Note TN2154 UIScrollView And Autolayout .

Your way let the system cannot decide scrollView's contentSize.

The main idea is let the scrollView knows what's the contentSize no matter which way you choose.

ScrollViews are a little bit more complicated when using auto layout. The frame is defined from the constraints with the other views (for you would be the ones you add in constainScrollView method).

But the contentSize is defined depending on the constraints from the views inside the scrollView . For your case, the contentSize is (0,0) because the inner view has no width or height constraint.

I suppose you would like this inner view to fill the scrollview. Then your constraints should look something like this:

- (void)constrainContentView
{
    [self.view layoutIfNeeded]; // This causes the scrollview width and height to be calculated based on the constraints you sent in the previous method
    // You could check by adding a breakpoint here, if the scrollview has the frame you would expect

#pragma contentView vertical constraints
    NSArray *cns = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[contentView(height)]-|"
                                              options:0
                                              metrics:@{"height":@(CGRectGetHeight(scrollView.frame))}
                                                views:NSDictionaryOfVariableBindings(scrollView, contentView)];
    [scrollView addConstraints:cns];

#pragma contentView horizontal constraints
    cns = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[contentView(width)]-|"
                                              options:0
                                              metrics:@{"width":@(CGRectGetWidth(self.view.frame))}
                                                views:NSDictionaryOfVariableBindings(scrollView, contentView)];
    [scrollView addConstraints:cns];
}

The actual value you set for the width and height depends on your needs.

The important thing is that the views inside the scrollView need to have the constraints in such a way setup that the contentSize can be calculated without ambiguity. This means if the view does not have an intrinsic size (like a UIButton or UILabel ) you need to add the width/height constraints explicitly.

Because of setting the width and height explicitly, on orientation change you would need to update the constraints so that the views inside have the right dimensions.

Hope this fixes your problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM