Setting view contraints programmatically - ios

I want to set a view constraint on the bottom of self.view programmatically in viewDidLoad. I want the view to end 80px above the bottom of the screen.
How would I go about doing this?

Looking at the AutoLayout guide, it looks like what you could do is something like this:
NSLayoutConstraint *myNewConstraint = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual toItem:self.view.window
attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-80.0];
and once you have that constraint created, you need to install it into the view... using something like:
[self.view addConstraint:myNewConstraint];
Now I've never done this, so the values might be a bit off. But hopefully this sends you down the right path!

Related

iOS - replicating a constraint programmatically

I created this constraint in Interface Builder. Without it, the below textview expands upwards as its content grows, with it, the textview expands downwards as its content grows.
How do I create that constraint in programmatically?
Here is what I tried:
[self addConstraint:[NSLayoutConstraint
constraintWithItem:_textView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_internalScrollView //this is the parent view
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0]];
but it has no material affect on anything.
The UITextView object I am using is from this library https://github.com/MatejBalantic/MBAutoGrowingTextView but that is a red herring to this question.
Here is what you need to do.
[_internalScrollView addConstraint:[NSLayoutConstraint
constraintWithItem:_textView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:_internalScrollView //this is the parent view
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:300.0]]; // constant should be 300 as shown by you in screen shot
btw, the above screen shot shows you are making constraint with top layout guide and not with parent view of textView if that is the case then layout attributes should be changed in the above code according to your needs

Autolayout and UIScrollview and Child View Controller issues

In my app I have an embedded child view controller into which at runtime I have to add one or more "Editor UIView"s based on data coming in from the server. I could model each "Editor" as a complete UIViewController in a xib file and add it at run time. The parent of the "Editor" has some items of its own (like titles and a couple of buttons) so I've tried to build a layered approach using a single child UIViewController and loading the "Editors" into its UIScrollview on the fly. However I can't get Autolayout to cooperate. This diagram shows the basic arrangement.
The problems start with just having the "Content View" embedded in the UIScrollview. I can get the content view to work OK with the scrollview. When I add the editor view and add runtime constraints to the content view, I get multiple auto layout complaints plus the scroll view content size is 0,0 so I am clearly not getting what I need.
Any ideas on how to approach this? I could always simply duplicate the child controller's extra items for each editor but it would be nice to have this work in this layered fashion.
Note I did this first with a UITableViewController where each editor is a UITableViewCell and that auto layout liked but I wanted to see if I could do it without the table. Maybe I will go back to that.
Added these at runtime:
_editor = [self editorForDataType];
[_contentView addSubview:_editor];
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:_editor
attribute:NSLayoutAttributeLeading
relatedBy:0
toItem:self.contentView
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0];
[self.contentView addConstraint:leftConstraint];
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:_editor
attribute:NSLayoutAttributeTrailing
relatedBy:0
toItem:self.contentView
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:0];
[self.contentView addConstraint:rightConstraint];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:_editor
attribute:NSLayoutAttributeLeading
relatedBy:0
toItem:self.contentView
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0];
[self.contentView addConstraint:topConstraint];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:_editor
attribute:NSLayoutAttributeTrailing
relatedBy:0
toItem:self.contentView
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0];
[self.contentView addConstraint:bottomConstraint];
In the end the key to what I needed was the follow set of constraints, plus adding the constraints for the editor view in viewDidLayoutSubviews and saving a property for the content view Height.
In viewDidLoad I set the height property to the height of the editor view. Now it works great.
Your last two constraints are incorrect. You have leading to top and trailing to bottom, those should be top to top and bottom to bottom. However, those constraints probably aren't what you want. If it's the first editor view, you probably want the top constraint to the content view and a height constraint. For any subsequent ones, you should pin the top to the editor view above it, rather than the content view.

iOS: Autolayout differences with appliying constraints to subview on iOS 7 and iOS 8

I have a view controller set up in a storyboard. The view controller's view contains a subview(UITableView) with pinned edges to the 4 sides of its parent, essentially making the view fill its parent.
I am adding the view controller's main view as a subview of another view controller's view like this:
UIView *overlayView = firstViewController.view;
[overlayView setTranslatesAutoresizingMaskIntoConstraints:NO];
UIView *sourceView = secondViewController.view;
[sourceView addSubview:overlayView];
NSLayoutConstraint *constraint;
constraint = [NSLayoutConstraint constraintWithItem:overlayView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:sourceView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0];
[sourceView addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:sourceView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:overlayView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:100];
[sourceView addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:overlayView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:sourceView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
[sourceView addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:overlayView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:sourceView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
[sourceView addConstraint:constraint];
[sourceView layoutIfNeeded];
I want to have a gap from the right edge of the view to its parent equal to 100 pixels.
Now weirdly enough this works as expected on iOS 8, but fails to do so on iOS 7 and the view is displayed full-screen ignoring the 100 constant set on the trailing constraint. Also, if the view controller's view that is being added has no child views - then it is working as expected. Is setTranslatesAutoresizingMaskIntoConstraints: being applied to all the subviews of a view in iOS 7 ? What might be the reason for this ?
EDIT:
The issue lies somewhere in the way subviews are being managed by the OS.
When the Container View is set as a outlet to the view property of the view controller, things don't work. If however, I set the Table View as an outlet to the view property, the it works. Something weird happens if there is a child view with pinned edges to its superview and then I am adding other constraints to the superview. I dont understand why it works fine on iOS 8 though...
EDIT 2
The problem seems to happen only with the trailing constraint. If I want to modify the constants of any of the other constraints there are no issues ?!
Can you try interchanging sourceView with overlayView in your constraint?
`constraint = [NSLayoutConstraint constraintWithItem:sourceView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:overlayView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:100];`
This essentially means that sourceView.trailing - 100 = overlayView.trailing; which is not what you would want.
Edit 1:
Is setTranslatesAutoresizingMaskIntoConstraints: being applied to all the subviews of a view in iOS 7?
NO. translatesAutoresizingMaskIntoConstraints is set only for the views you explicitly call setTranslatesAutoresizingMaskIntoConstraints for.

iOS Auto Layout issue

I'm trying to make constraints programmatically. I have textField and button created in IB. Here is the code:
UIView *superview = self.view;
self.button.translatesAutoresizingMaskIntoConstraints = NO;
self.textField.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.textField
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:0];
[superview addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:self.textField
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeCenterX
multiplier:1.0f
constant:0];
[superview addConstraint:constraint];
constraint =[NSLayoutConstraint constraintWithItem:self.button
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.textField
attribute:NSLayoutAttributeLeading
multiplier:1
constant:-10];
[superview addConstraint:constraint];
constraint =[NSLayoutConstraint constraintWithItem:self.button
attribute:NSLayoutAttributeBaseline
relatedBy:NSLayoutRelationEqual
toItem:self.textField
attribute:NSLayoutAttributeBaseline
multiplier:1
constant:0];
[superview addConstraint:constraint];
And after running I have this issue:
Constraints also have no effect on views.
What am I doing wrong?
First in the storyboard editor select the view controller you want to change then, in the constraint editor, select "ADD missing constraints in view controller"
Select an elment that you'd like to modify at runtime by remomiving and adding new constraint, in the object inspector panel select each constraints and edit it by checking the box "placeholder: remove at build time".
This is a way to say to storyboard editor that you are fine with the constraint ant it should not apply or complain about an insufficient constraints situation.
Constraints flagged are removed at runtime, so you should provide you own constraint and is better if you do in the right place. Ovverride -updateViewConstraints in the view controller and remember to call super and add you new constraints.
You have three auto-generated constraints "IB auto generated at build time for view with fixed frame". These conflict with the ones you make yourself. Probably, you have set fixed size properties on the text field and button in Interface Builder. Possibly, you have a fixed width on your button, and that conflicts with the trailing constraint.
Combining IB with code constraints can be tricky. I have found it is often easier to design things only in IB or only in code to avoid conflicts like these, although combining the two is perfectly viable.
For a good explanation on what NSIBPrototypingLayoutConstraint is, have a look at this SO answer:
Trouble with AutoLayout on UITableViewCell

Auto Layout - programatically defining unusual constraints

I'm trying to find examples for some relatively nonstandard layouts, but all the documentation I found only gave examples of centring or aligning with the superview borders, or giving fixed numbers as spaces and sizes.
Can you please advise about programatically defining the following constraints:
A. Diagonal views:
B. Put a view on the third of it's superview's border (or some other ratio which is not the middle)
C. Two standard spaces from the superview's border (like this |-[v1], but with double space)
Any documentation that discusses similar cases would be also highly appreciated :)
Thanks in advance!
You can use the verbose NSLayoutContraint method to create any constraint, that can't be expressed with the visual format language.
A: You need two constraint that describe exactly what you want. In this case you want the top edge of v1 and the bottom edge of v2 be the same. Similarly for the right and left edges.
NSLayoutConstraint *constraint;
constraint = [NSLayoutConstraint constraintWithItem:v1
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:v2
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0];
[self.view addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:v1
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:v2
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0.0];
[self.view addConstraint:constraint];
B: This time you want to top edge of v1 and v2 to be the same:
NSLayoutConstraint *constraint;
constraint = [NSLayoutConstraint constraintWithItem:v2
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:v1
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0];
[self.view addConstraint:constraint];
What constraint to use for the horizontal position of the orange view, depends on what you want. Do you want a fixed margin to the right edge of the blue view?
constraint = [NSLayoutConstraint constraintWithItem:v2
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:v1
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:rightMargin];
[self.view addConstraint:constraint];
C: I don't think you can specify a double space like that. You could either use an ugly trick, and insert an invisible (width 0) view between the standard spaces like this:
|-[invisibleView(0)-[v1]
Or you could just figure out what the standard margin is, and use twice that value as a constant:
|-(doubleMargin)-[v1]

Resources