Search code examples
uiscrollviewautolayoutcontentsize

CustomView with Dynamic ScrollView ContentSize Autolayout called in addSubview


I have a customView created in xib with height = 800 :

customView with 800 height

I want to call it via addSubview into the blue view as shown in the UIViewController :

wantToShowHereView in UIViewController

the problem here is I want my UIScrollView can dynamically set it's contentSize, because here I define it's height to 800 :

enter image description here

I read from another article that the contentSize in AutoLayout will be defined by the height of its subView, in this case the contentView. but still after I set the height to 800 the scroll is not reaching the bottom of the view (pink). how to set the autolayout then?

Broken ScrollView

here is my code in the customView :

- (id)initWithFrame:(CGRect)frame
{
NSLog(@"initWithFrame");
self = [super initWithFrame:frame];
if (self) {
    [self setup];
}
return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder {
NSLog(@"initWithCoder");
self = [super initWithCoder:aDecoder];
if(self) {
    [self setup];
}
return self;
}

- (void)setup {

[[NSBundle mainBundle] loadNibNamed:@"customView" owner:self options:nil];
[self addSubview:self.view];
NSLog(@"contentSize Height :%f", self.myscrollview.contentSize.height);
NSLog(@"contentView Height :%f", self.contentView.frame.size.height);
}

in my ViewController.m i called it like this :

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

customView *customV = [[customView alloc] initWithFrame:self.wantToShowHereView.bounds];
[self.wantToShowHereView addSubview:customV];

}

Can someone give me direction on how I want to achieve it? Here is my example project to make it clear for you : AutoLayoutScrollView Example


Solution

  • Couple of issues.

    First, you are setting the frame of customV to the bounds of wantToShowHereView -- but you're doing so in viewDidLoad(). That bounds will almost certainly change between viewDidLoad() and the time you actually see it on screen (device size, orientation, etc).

    Second, customV is a UIView onto which you are adding the XIB's "root view" (which contains your scroll view) as a subview to customV ... but you're not setting any constraints (or other resizing behaviors) on that view.

    Third, you're mixing relative constraints with absolute constraints (widths, heights, leading, trailing, etc), which will again cause issues when the overall frame changes... and you're explicitly setting the frame of customV instead of adding constraints at run-time.

    You can get a start on fixing things:

    Step one - remove customV instantiation from viewDidLoad().

    Step two - add the following viewDidAppear() method.

    - (void)viewDidAppear:(BOOL)animated {
    
        [super viewDidAppear:animated];
    
        customView *customV = [[customView alloc] initWithFrame:self.wantToShowHereView.bounds];
        customV.view.frame = customV.bounds;
        [self.wantToShowHereView addSubview:customV];
    
    }
    

    Doing only that should give you a properly scrollable view.

    What you probably want to do, though, is keep the init in viewDidAppear() but add constraints there to make use of auto-layout.

    Also, I'd recommend re-working the constraints on the elements in your customView.xib so the scrolling (the contentSize) is determined by the actual content of your scroll view, not by hard-coding a height of your contentView.


    Edit:

    Here is how your viewDidLoad could look (in ViewController.m):

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        customView *customV = [[customView alloc] initWithFrame:self.wantToShowHereView.bounds];
        [self.wantToShowHereView addSubview:customV];
    
        customV.translatesAutoresizingMaskIntoConstraints = NO;
    
        [customV.topAnchor constraintEqualToAnchor:self.wantToShowHereView.topAnchor].active = YES;
        [customV.bottomAnchor constraintEqualToAnchor:self.wantToShowHereView.bottomAnchor].active = YES;
        [customV.leadingAnchor constraintEqualToAnchor:self.wantToShowHereView.leadingAnchor].active = YES;
        [customV.trailingAnchor constraintEqualToAnchor:self.wantToShowHereView.trailingAnchor].active = YES;
    
    }
    

    and setup in customView.m:

    - (void)setup {
    
        [[NSBundle mainBundle] loadNibNamed:@"customView" owner:self options:nil];
        [self addSubview:self.view];
    
        self.view.translatesAutoresizingMaskIntoConstraints = NO;
    
        [self.view.topAnchor constraintEqualToAnchor:self.topAnchor].active = YES;
        [self.view.bottomAnchor constraintEqualToAnchor:self.bottomAnchor].active = YES;
        [self.view.leadingAnchor constraintEqualToAnchor:self.leadingAnchor].active = YES;
        [self.view.trailingAnchor constraintEqualToAnchor:self.trailingAnchor].active = YES;
    
        NSLog(@"contentSize Height :%f", self.myscrollview.contentSize.height);
        NSLog(@"contentView Height :%f", self.contentView.frame.size.height);
    
    }