Constrain width of UIStackView arranged views inside UIScrollView - ios

I have embedded a UIStackView inside a UIScrollView. When I add a view as an arranged subview to the UIStackView, its width expands beyond the frame and causes a horizontal scrollbar to appear, even when I add horizontal width layout constraints. I do not want the UIScrollView to expand horizontally.
The code for programatically creating the UIStackView inside the UIScrollView in viewDidLoad:
_scrollView = [UIScrollView new];
_scrollView.delegate = self;
_scrollView.translatesAutoresizingMaskIntoConstraints = NO;
_scrollView.pagingEnabled = YES;
[self.view addSubview:_scrollView];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[scrollView]|" options:NSLayoutFormatAlignAllCenterX metrics:nil views:#{#"scrollView": _scrollView}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[scrollView]|" options:NSLayoutFormatAlignAllCenterX metrics:nil views:#{#"scrollView": _scrollView}]];
// configure stackView
_stackView = [UIStackView new];
_stackView.translatesAutoresizingMaskIntoConstraints = NO;
_stackView.axis = UILayoutConstraintAxisVertical;
[_scrollView addSubview:_stackView];
[_scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[stackView]|" options:NSLayoutFormatAlignAllCenterX metrics:nil views:#{#"stackView": _stackView}]];
[_scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[stackView]|" options:NSLayoutFormatAlignAllCenterX metrics:nil views:#{#"stackView": _stackView}]];
Then I add my custom view, and an AutoLayout constraint to limit the subview's width to the stackView's:
CustomView *customView = [CustomView loadFromXib]; // helper to load from xib
[_stackView addArrangedSubview:customView];
[_stackView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[customView]|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:#{#"customView": customView}]];
However, the resulting CustomView is about double the width of the frame. None of the IB-set constraints in CustomView have fixed widths, so I would expect the content to resize to fit the frame. What am I doing wrong?

Related

AutoLayout programmatically doesn't work

I want to go into the depths of auto layout and so I want to do it programmatically in order to understand it properly.I know how to use it through storyboard pretty well.Now here is what I am doing(in viewDidAppear:)
-(void)scenario2{
PGView *viewA = [[PGView alloc]initWithFrame:CGRectMake(100, 100, 100, 100) andBackgroundColor:[UIColor blackColor]];
[self.view addSubview:viewA];
PGView *viewB = [[PGView alloc]initWithFrame:CGRectMake(200, 300, 100, 100) andBackgroundColor:[UIColor yellowColor]];
[self.view addSubview:viewB];
viewA.translatesAutoresizingMaskIntoConstraints = NO;
viewB.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *constraint;
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];
//problem statement
constraint = [NSLayoutConstraint constraintWithItem:viewA attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:viewB attribute:NSLayoutAttributeWidth multiplier: 3.0f constant: 0.0f];
[self.view addConstraint:constraint];
NSLog(#"%#",viewA);
NSLog(#"%#",viewB);
}
So here I have initialized two views with different colors.
I know I need to set the property. translatesAutoresizingMaskIntoConstraints to NO before applying any new constraints. So I have done that.
Now I am specifying heights and widths of both the views.So,the x_position and y_position for both the views are 0.I run the code and I get the expected result. Both views have the specified height and width at point (0,0).
Problem
Now when I am writing the statement "problem statement" to adjust the width of viewB according to the width of viewA,its not working.
Also, when I print views viewA and viewB,it prints the frames as (0,0,0,0).
Can anyone explain me this behavior?
Edit:Here are some modifications that I have made.I have checked the ambiguity of both the views using 'hasAmbiguousLayout' and its working fine now.Now what should be the next step if I want to resize viewB's width thrice to that of viewA's width?
-(void)scenario2{
PGView *viewA = [PGView new];
viewA.backgroundColor = [UIColor yellowColor];
[self.view addSubview:viewA];
PGView *viewB = [PGView new];
viewB.backgroundColor = [UIColor blackColor];
[self.view addSubview:viewB];
viewA.translatesAutoresizingMaskIntoConstraints = NO;
viewB.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *constraint;
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];
NSLog(#"%d",viewA.hasAmbiguousLayout);
NSLog(#"%d",viewB.hasAmbiguousLayout);
NSLog(#"%#",viewA);
NSLog(#"%#",viewB);
}
The problem is that you've explicitly set width constraints for A and B to be 200 and 100, respectively. So the additional constraint that specifies that one should have a width of three times the other one is unsatisfiable when combined with the other constraints.
Furthermore, the constraints are ambiguous, as you've defined width and height constraints, but haven't defined where the two frames should be. Yes, you've defined the frame for these two views, but that is ignored when you apply the constraints. You probably shouldn't define the frame values at all, as it's misleading and confusing. But you should set, for example, the leading and top constraints, or specify those in the VFL, or add centerX and centerY constraints. You just want some constraints to dictate where the views should be placed and there's lots of ways to specify that.
And the reason that you're not seeing reasonable frame values at the end is that you've defined the constraints, but they haven't been applied yet. You could examine them in viewDidLayoutSubviews, if you wanted.
You might do something like:
- (void)scenario2 {
PGView *viewA = [PGView new];
viewA.backgroundColor = [UIColor yellowColor];
[self.view addSubview:viewA];
PGView *viewB = [PGView new];
viewB.backgroundColor = [UIColor blackColor];
[self.view addSubview:viewB];
viewA.translatesAutoresizingMaskIntoConstraints = NO;
viewB.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary *views = NSDictionaryOfVariableBindings(viewA, viewB);
// note, I added `|-100-` to say it's 100 points from the top (and 100 tall)
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-100-[viewB(==100)]" options:0 metrics:nil views:views]];
// likewise, to say 200 points from the left (and 100 wide)
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-200-[viewB(==100)]" options:0 metrics:nil views:views]];
// again, 100 from the top (as well as 200 tall)
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-100-[viewA(==200)]" options:0 metrics:nil views:views]];
// and 100 from the left
// but I've removed width definition, as we'll use your multiplier constraint below
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-100-[viewA]" options:0 metrics:nil views:views]];
// now that we've removed the width constraint from the above,
// this should now work fine
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:viewA attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:viewB attribute:NSLayoutAttributeWidth multiplier: 3.0f constant: 0.0f];
[self.view addConstraint:constraint];
// no point in doing this, because constraints haven't yet been applied
//
// NSLog(#"%#",viewA);
// NSLog(#"%#",viewB);
}
// if you want to see where they are, you could do that here:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
for (UIView *view in self.view.subviews) {
NSLog(#"%#", view);
}
NSLog(#"-----");
}

need help in autolayout top layout guide, UIscrollView, UIImageView

I am working on a top sticked streach header.
My setup:
UIScrollView
-UIView(a container)
-UIImageView
-UIView(subContent view)
What i want:
Stick UIImageView to top layout guide.
UIImageView height is 100 - 250. That is UIImageView height is initialise with 250, but can not be less than 100.
0 top space in between UIImageView and subContentView.
So when user scroll towards bottom, UIImageView will gradually minimise and will no more minimise as soon as it's height reaches 100(minimum height).
BUT subContentView must not overlap my UIImageView and be able to scroll till end (accurate content size/ offset)
What i am able to do is:
i am able to stick UIImageView to top based on layout guide.
I am also able to acheive height range of UIImageView on scroll top or bottom (increase and decrease height).
BUT i am not able to stop UIImageView from being overlapping by my subContentView.
That is when i scroll to bottom my UIImageView remains stick to top and gradually decreases it's size, at the moment it reaches to height 100,(i am still scrolling bottom) my subContentView starts overlapping my UIImageVIew.
How ever it makes sense as i have no set constraints from top layout guide to subcontent view.
some thing like:
format = #"V:|[topGuide]-**some dynamic value based on UIImageViewHeight**-[subContentView]";
How do i achieve this.
Please help me i am working on it from a day, and finally i decided to ask.
my code:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.navigationItem.title = #"Programmatically";
NSMutableDictionary* views = [NSMutableDictionary new];
views[#"super"] = self.view;
views[#"topGuide"] = self.topLayoutGuide; // The bottom of the navigation bar, if a navigation bar is visible. The bottom of the status bar, if only a status bar is visible .. etc...
//Create the ScrollView
UIScrollView* scrollView = [UIScrollView new];
scrollView.delegate = self;
scrollView.translatesAutoresizingMaskIntoConstraints = NO; //we are using auto layout
self.automaticallyAdjustsScrollViewInsets = NO;
[self.view addSubview:scrollView];
views[#"scrollView"] = scrollView;
//Create the scrollview contentview
UIView* contentView = [UIView new];
[contentView setBackgroundColor:[UIColor yellowColor]];
contentView.translatesAutoresizingMaskIntoConstraints = NO; //we are using auto layout
[scrollView addSubview:contentView];
views[#"contentView"] = contentView;
//Add the image view and other addtional views to the content view
topImageView = [[WAPlayerDetailHeader alloc] initWithFrame:CGRectZero andImage:nil];
topImageView.translatesAutoresizingMaskIntoConstraints = NO; //we are using auto layout
topImageView.contentMode = UIViewContentModeScaleAspectFill;
topImageView.clipsToBounds = YES;
[contentView addSubview:topImageView];
views[#"topImageView"] = topImageView;
//Add other content to the scrollable view
UIView* subContentView = [UIView new];
[subContentView setBackgroundColor:[UIColor redColor]];
subContentView.translatesAutoresizingMaskIntoConstraints = NO; //we are using auto layout
[contentView addSubview:subContentView];
views[#"subContentView"] = subContentView;
//Now Let's do the layout
NSArray* constraints;
NSString* format;
NSDictionary* metrics = #{#"imageHeight" : #250.0};
//======== ScrollView should take all available space ========
format = #"|-0-[scrollView]-0-|";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[self.view addConstraints:constraints];
format = #"V:[topGuide]-0-[scrollView]-0-|";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[self.view addConstraints:constraints];
//======== ScrollView Content should tie to all four edges of the scrollview ========
format = #"|-0-[contentView]-0-|";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[scrollView addConstraints:constraints];
format = #"V:|-0-[contentView]-0-|";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[scrollView addConstraints:constraints];
// ========== Layout the image horizontally
format = #"|-0-[topImageView(==super)]-0-|"; // with trick to force content width
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[self.view addConstraints:constraints];
// ========== Put the sub view height, and leave room for image
format = #"|-0-[subContentView]-0-|";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[scrollView addConstraints:constraints];
// we leave some space between the top for the image view
format = #"V:|-imageHeight-[subContentView(1000)]-0-|"; /*the view height is set to 700 for the example in order to have enough content */
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:metrics views:views];
[scrollView addConstraints:constraints];
// Start of the magic
format = #"V:[topImageView]-0-[subContentView]"; // image view bottom is subcontent top
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[contentView addConstraints:constraints];
// image view top is the top layout
format = #"V:|[topGuide]-0-[topImageView(>=100)]";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[self.view addConstraints:constraints];
//Optional stuff, Add The A view
aView = [[WAPlayerDetailHeader alloc] initWithFrame:CGRectZero andImage:nil];
[aView setAlpha:1.0];
aView.translatesAutoresizingMaskIntoConstraints = NO; //we are using auto layout
aView.backgroundColor = [UIColor colorWithRed:0.79 green:0.9 blue:0.69 alpha:1];
[subContentView addSubview:aView];
views[#"aView"] = aView;
format = #"|[aView]|";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[subContentView addConstraints:constraints];
format = #"V:|-[aView(127)]-5-|";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[subContentView addConstraints:constraints];
}
this is what happening video demo
i am following this code from this location
i have upload on git download and you can see

What auto layout constraints lets a subview to compress to 0 size when the parent's size decreases?

Trying to figure out what constraints do I need to add to a view-subview layout hierarchy that would allow the subview to auto resize when the parent view's size changes. Not using interface builder intentionally, translatesAutoresizingMaskIntoConstraints is set to NO for all participating views.
Below is a code snippet that tries to describe the situation:
UIView *canvas = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
container.translatesAutoresizingMaskIntoConstraints = NO;
[canvas addSubview:container];
NSNumber *height = #(50);
NSNumber *margin = #(10);
NSDictionary *metrics = NSDictionaryOfVariableBindings(height, margin);
NSDictionary *views = NSDictionaryOfVariableBindings(container);
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(margin)-[container(height)]" options:0 metrics:metrics views:views];
[canvas addConstraints:constraints];
NSLayoutConstraint *containerHeightConstraint = [constraints objectAtIndex:1]; // Know this is unsafe and shouldn't use the visual format in this case, but visual format serves SO purposes better
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"|-(margin)-[container]-(margin)-|" options:0 metrics:nil views:views];
[canvas addConstraints:constraints];
UIView *subView = [[UIView alloc] initWithFrame:CGRectZero];
subView.translatesAutoresizingMaskIntoConstraints = NO;
[container addSubview:subView];
margin = #(5);
metrics = NSDictionaryOfVariableBindings(margin);
views = NSDictionaryOfVariableBindings(subView);
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(margin)-[subView]-(margin)-|" options:0 metrics:metrics views:views];
[container addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"|-(margin)-[subView]-(margin)-|" options:0 metrics:metrics views:views];
[container addConstraints:constraints];
[container layoutIfNeeded]; // Layout before animation
containerHeightConstraint.constant = 0;
[UIView animateWithDuration:animationDuration animations:^{
[container layoutIfNeeded]; // Animate container to 0 height
} completion:nil];
The question is what constraints do I need to add that would mimic the autoresize mask constraints that Interface Builder creates and would allow subView in the above example to shrink to 0 height as container shrinks.
If you could also explain the mechanics of such constraints that would help me understand Auto Layout better.
All you need is to set the height and width constant constrain to your subview when the container resizes.

Adding a background imageview programmatically with autolayout

I need to add a background image view for my views for a project I've done using storyboards + autolayout. I want to add this image programmatically using code. so basically it should be from top layoutguide to bottom layoutguide, without going under them. I've tried few ways which failed horribly.
one way I first adjust the VC'c view before adding like this
id topGuide = self.topLayoutGuide;
UIView *superView = self.view;
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings (superView, topGuide);
[self.view addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"V:[topGuide]-20-[superView]"
options:0
metrics:nil
views:viewsDictionary]
];
[self.view layoutSubviews];
but for some reason my imageview still goes under statusbar.
this is how I add the bg imageview
self.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Default"]];
self.backgroundView.contentMode = UIViewContentModeTop;
[self.view insertSubview:self.backgroundView atIndex:0];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[backgroundImageView]|" options:0 metrics:nil views:#{#"backgroundImageView":self.backgroundView}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[backgroundImageView]|" options:0 metrics:nil views:#{#"backgroundImageView":self.backgroundView}]];
Adding the constraint related to the topLayoutGuide to self.view is useless. The view controller layout its root view (self.view) independently from AutoLayout, and will override the constraints effects (don't quote me on this, this is an observation more than a real understanding of the layout system).
Instead, add the first constraint (#"V:[topGuide]-20-[superView]") to self.backgroundView:
self.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Default"]];
self.backgroundView.contentMode = UIViewContentModeTop;
[self.view insertSubview:self.backgroundView atIndex:0];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[topGuide]-(20)-[backgroundImageView]|" options:0 metrics:nil views:#{#"backgroundImageView":self.backgroundView, #"topGuide": self.topLayoutGuide}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[backgroundImageView]|" options:0 metrics:nil views:#{#"backgroundImageView":self.backgroundView}]];
[self.view layoutSubviews];

UIScrollView with iOS Auto Layout Constraints: Wrong size for subviews

I'm trying to generate a view in code. Here's the hierachy of my view object
UIScrollView
UIView
UIButton
The ScrollView should be the same size as the window.
The button should be as big as possible.
I'm using iOS auto layout, so the constraint strings for all of my objects look like this
H:|[object]|
V:|[object]|
I've also set translatesAutoresizingMaskIntoConstraints to NO for each object.
The problem is that the button only gets the default button-size. Its parent view object (UIView) only gets the size its subviews need.
red: UIScrollView / yellow: UIView
How can I force those views to be as big as the scrollView?
When I use a UIView instead of th UIScrollView everything works great...
Here's some code:
- (void) viewDidLoad {
[super viewDidLoad];
// SCROLL VIEW
UIScrollView* scrollView = [UIScrollView new];
scrollView.backgroundColor=[UIColor redColor];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
//CONTAINER VIEW
UIView *containerView = [UIView new];
containerView.translatesAutoresizingMaskIntoConstraints = NO;
containerView.backgroundColor = [UIColor yellowColor];
[scrollView addSubview:containerView];
// CONSTRAINTS SCROLL VIEW - CONTAINER VIEW
[scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[containerView]|"
options:0 metrics:nil
views:#{#"containerView":containerView}]];
[scrollView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[containerView]|"
options:0 metrics:nil
views:#{#"containerView":containerView}]];
// BUTTON
UIButton* button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.translatesAutoresizingMaskIntoConstraints = NO;
[button setTitle:#"I'm way to small" forState:UIControlStateNormal];
[containerView addSubview:button];
// CONSTRAINTS CONTAINER VIEW - BUTTON
[containerView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[button]|"
options:0 metrics:nil
views:#{#"button":button}]];
[containerView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[button]|"
options:0 metrics:nil
views:#{#"button":button}]];
self.view = scrollView;
}
UPDATE:
I really don't know, why this is happening. If you set up the view in IB, connect the outlets and instanciate the view in code, the scrollview behaves like a normal view (which bounces vertically). Its contentSize is not calculated correctly. More here. But how to do it correctly?
A couple of observations:
Constraints for subviews in scroll views don't work like constraints in other views. They're used to set the contentSize of the scroll view. (See TN2154.) That way, you throw a bunch of stuff on a scroll view, set the constraints for the stuff inside it, and the contentSize is calculated for you. It's very cool feature, but it's antithetical to what you're trying to do here.
Worse, buttons will, unless you set an explicit constraint for their width and height of a button, will resize according to their content.
The net effect of these two observations is that your existing constraints say "(a) set my container to be the size of my button; (b) let my button resize itself dynamically to the size of the text; and (c) set my scrollview's contentSize according to the size of my container (which is the size of the button)."
I'm unclear as to what the business problem is. But here are some constraints that achieve what I think your technical question was:
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *view = self.view;
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.backgroundColor = [UIColor redColor]; // just so I can see it
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:scrollView];
UIView *containerView = [[UIView alloc] init];
containerView.backgroundColor = [UIColor yellowColor]; // just so I can see it
containerView.translatesAutoresizingMaskIntoConstraints = NO;
[scrollView addSubview:containerView];
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.translatesAutoresizingMaskIntoConstraints = NO;
[button setTitle:#"I'm the right size" forState:UIControlStateNormal];
[containerView addSubview:button];
NSDictionary *views = NSDictionaryOfVariableBindings(scrollView, button, view, containerView);
// set the scrollview to be the size of the root view
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[scrollView]|"
options:0
metrics:nil
views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[scrollView]|"
options:0
metrics:nil
views:views]];
// set the container to the size of the main view, and simultaneously
// set the scrollview's contentSize to match the size of the container
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[containerView(==view)]|"
options:0
metrics:nil
views:views]];
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[containerView(==view)]|"
options:0
metrics:nil
views:views]];
// set the button size to be the size of the container view
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[button(==containerView)]"
options:0
metrics:nil
views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[button(==containerView)]"
options:0
metrics:nil
views:views]];
}
Frankly, I don't understand the business intent of your UI, as this feels like a contortion of auto layout to achieve a very simply UI. I don't know why you have a scroll view if you have "screen sized" content in it (unless you were paging through buttons). I don't know why you'd have a content view with a single item in it. I don't understand why you're using a full-screen button (I'd just put a tap gesture on the root view at that point and call it a day).
I'll assume you have good reasons for all of this, but it might make sense to back up, ask what is your desired user experience is, and then approach the problem fresh to see if there's a more efficient way to achieve the desired effect.

Resources