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]
Related
I want to show user that application is loading data using some progress bar and label on top of view which will be shown after the data is loaded. This view is not initial, so I cannot use LaunchScreen for these purposes. What's the best way to do so?
The view which will be shown after uses AutoLayout, and it'd better be that view on top uses AutoLayout as well, but those AutoLayouts shouldn't interact with each other in any way.
First create a custom UIView class, and customize the view according to your requirement. i.e. transparent background, add image/label etc. using autolayout/with the help of code.
Now add this custom view (yourSubView) into its containerview and add some constraint so that it place in right location.
The following code will add a subview after keep space 80px in all side (left, right, top, bottom), you can add constraint according to your requirement.
[yourContainerView addSubview:yourSubView];
yourSubView.translatesAutoresizingMaskIntoConstraints =
NO;
[yourContainerView addConstraint:[NSLayoutConstraint constraintWithItem:yourSubView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:yourContainerView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:80.0]];
[yourContainerView addConstraint:[NSLayoutConstraint constraintWithItem:yourSubView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:yourContainerView attribute:NSLayoutAttributeRight multiplier:1.0 constant:80.0]];
[yourContainerView addConstraint:[NSLayoutConstraint constraintWithItem:yourSubView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:yourContainerView attribute:NSLayoutAttributeTop multiplier:1.0 constant:80.0]];
[yourContainerView addConstraint:[NSLayoutConstraint constraintWithItem:yourSubView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:yourContainerView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:80.0]];
What about using something like https://github.com/sgryschuk/SGNavigationProgress?
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
I'm using the UIView+Autolayout library to make code-based Auto Layout constraint creation easier, but I'm having trouble adding a constraint with this library.
What I'm trying to do is this:
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.captionLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.captionLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
Which uses the normal NSLayoutConstraint addition methods, and it works beautifully. But when I try to do something similar with UIView+Autolayout:
[self.captionLabel autoAlignAxisToSuperviewAxis:ALAxisHorizontal];
[self.captionLabel autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:20.0];
It comes out aligned in the middle vertically and off to the left side.
What am I doing wrong for setting this up?
The code you shared using the NSLayoutConstraint API:
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.captionLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.captionLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
Would translate into the following using the UIView+AutoLayout API:
[self.captionLabel autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:0.0];
[self.captionLabel autoAlignAxisToSuperviewAxis:ALAxisVertical];
Note that ALAxisVertical is the correct constant to use, not ALAxisHorizontal as you originally had. To understand why, take a look at the comments where this enum is defined:
typedef NS_ENUM(NSInteger, ALAxis) {
ALAxisVertical = NSLayoutAttributeCenterX, // a vertical line through the center of the view
ALAxisHorizontal = NSLayoutAttributeCenterY, // a horizontal line through the center of the view
ALAxisBaseline = NSLayoutAttributeBaseline // a horizontal line at the text baseline (not applicable to all views)
};
If you align the vertical axes of two views, as we are doing here, you end up adjusting their x-position and/or size so that they end up (what you might describe as) centered horizontally. That's likely where some confusion lies. As always, a picture is worth a thousand words:
When you understand how the ALAxis constants are defined and think about it visually, it makes sense (and you'll see that it is consistent with how these constants get used throughout the API).
I will be short and very clear. I want to do what's on the figure below using constraints.
Any suggestions or solutions?
Description:
The coloured places are UIViews, containing for ex. 4 labels. So what constraint should I use to manipulate with the second UIView so in Portrait mode to be under the first one and in Landscape to be next to it?
The code below assumes you already have a reference to the orange view and the yellow view in your code. When in portrait mode you want them to be in sequence so you can have a layout as such
NSLayoutConstraint *portraitConstraint = [NSLayoutConstraint
constraintWithItem:orangeView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:yellowView
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:2.0f];
[self.view addConstraint:portraitConstraint];
When in landscape mode you can have a layout constraint as such
NSLayoutConstraint *landscapeConstraint = [NSLayoutConstraint
constraintWithItem:orangeView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:yellowView
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:2.0f];
[self.view addConstraint:landscapeConstraint];
Now these are not the full list of constraints you would need, if you build in the code and only the code you would have to have the orange view stick to the top, leading and trailing of the view and then in the code have the yellow view stick to the leading, trailing and bottom in the view for portrait.
In landscape you would have the orange view stick to the top, bottom and leading while the yellow view would stick to the top, bottom and trailing.
The constraints that are above would allow so you do not need a height to be set, but you might want to also say something like the orange view bottom is centerY - 1.0 in portrait and centerX - 1.0f in landscape thus avoiding the need for widths and heights and hence not worrying about the size of the screen. Center X and Y are below
NSLayoutConstraint *centerX = [NSLayoutConstraint
constraintWithItem:orangeView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0f
constant:-1.0f];
[self.view addConstraint:centerX];
NSLayoutConstraint *centerY = [NSLayoutConstraint
constraintWithItem:orangeView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:-1.0f];
[self.view addConstraint:centerY];
The above constraints should help you on your way to resolving the issue.
I am building an app with a modal view containing a UICollectionView and below it a view containing two buttons (validate/cancel).
The number of rows in my UICollectionView can change depending on the data and don't know it beforehand so I want to add a constraint to always keep my buttons 30px below the collectionView.
I am not using auto-layout for this as I have some animations which work better without it so I don't know how to programmatically add such constraints.
Does anyone have any idea how to do it?
Many thanks for your help
I am not sure about the collection view. However, the below works with a standard view and since UICollectionView is a type of UIView, then the code might work with collection view also
NSLayoutConstraint *bottomConstraint=[NSLayoutConstraint constraintWithItem:buttonA attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:0.45 constant:0];
NSLayoutConstraint *widthConstraint=[NSLayoutConstraint constraintWithItem:buttonA attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:95];
NSLayoutConstraint *heightConstraint=[NSLayoutConstraint constraintWithItem:buttonA attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:95];
NSLayoutConstraint *leftConstraint=[NSLayoutConstraint constraintWithItem:buttonA attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:20];
[self.view addConstraints:#[bottomConstraint,widthConstraint,heightConstraint,leftConstraint]];
The above basically lays out the buttonA relative to the view. However, to use this, the auto layout should be off (as in your case).
The bottom Constraint says that this constraint is related to button A and will act on its attribute NSLayoutAttributeBottom(bottom side) and the bottom side will be present on exactly 0.45*(Bottom of view).
The width constraint specifies that it is related to button A and will act on its width. The width is not dependent on any other object (toItem is nil) and it will have a constant value of 95.