iOS Auto Layout When Loading Another Nib - ios

I have a detail view in a story board. I want to load another Nib in that view when a certain condition is met. But when I do, the auto layout its all screwed you.
I am trying to display the UIView above the UIWebView like an overlay view. I want the UIView to have the same ratio of the device with a maximum height of 400 between the top and bottom layout guide.
Here is the code I used to load the Nib:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController.navigationBar setTintColor:[UIColor whiteColor]];
// Do any additional setup after loading the view, typically from a nib.
UINib *s = [UINib nibWithNibName:#"Square1" bundle:nil];
NSArray *array = [s instantiateWithOwner:self options:nil];
StopView *stopView = (StopView *)[array objectAtIndex:0];
[stopView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:stopView];
id topGuide = self.topLayoutGuide;
id bottomGuide = self.bottomLayoutGuide;
UIWebView *webView = self.detailWebView;
NSDictionary *views = NSDictionaryOfVariableBindings(stopView, topGuide, bottomGuide, webView);
// this is here to stop the auto layout from reporting that the guides has
// ambiguous layout
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[topGuide]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[bottomGuide]|" options:0 metrics:nil views:views]];
// center the stop view in the super view, both lines below are needed
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|-(>=12)-[stopView(<=400)]-(>=12)-|"
options: 0
metrics:nil
views:views]];
// set the height to a ratio of the width
NSLayoutConstraint *con2 = [NSLayoutConstraint constraintWithItem:stopView
attribute:NSLayoutAttributeWidth
relatedBy:0 toItem:stopView
attribute:NSLayoutAttributeHeight
multiplier:0.66667f constant:0];
[self.view addConstraint:con2];
// center the Stop View X,Y with the super view
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:stopView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0f constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:stopView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1.0f constant:0]];
NSLog(#"Calling configureView from viewDidLoad");
[self configureView];
}
Here are some screen shots:
As you can see in the third screen shot, my background is not showing. And you can see the T from the UILabel that placed at the top in design mode.
What am I doing incorrectly?

For a vertical constraint, you need to put a "V:" in front of the string. To get a view to be 400 max, but be as big as it can given the top and bottom spacing constraints for a smaller screen, you need to use the priority of the constraint,
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(>=12)-[stopView(==400#900)]-(>=12)-|"
options: 0
metrics:nil
views:views]];
The system will try to make the height of stopView as close to 400 as possible while maintaining a spacing of at least 12 to the top and bottom.

Related

AwakeFromNib auto layout stretch UIlabel to spacing on both side programmatically

I am trying to add a UIlabel to a UIView class.
it should be in the following format -15-Label(stretch to max width)-15.
Top spacing=15 and height fixed to 30.
Two issues with the following code:-
1) Label does not stretch to max width
2) Right side spacing does not show up , if the text it too long.
-(void)awakeFromNib{
[super awakeFromNib];
view1 =[[UILabel alloc] init];
view1.translatesAutoresizingMaskIntoConstraints=NO;
[self addSubview:view1];
view1.text= #"Hello";
NSDictionary *constraintViews=
#{#"view1":view1};
NSDictionary *metrics=#{#"spacing":#(15)};
NSArray *hConstraints=[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-spacing-[view1]-spacing-|" options:NSLayoutFormatAlignAllCenterX metrics:metrics views:allViews];
NSArray *vConstraints=[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-spacing-[view1(30)]" options:0 metrics:metrics views:constraintViews];
[self addConstraints:hConstraints];
[self addConstraints:vConstraints];
}
1)
Update the horizontal constraints like so:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-spacing-[view1]-spacing#751-|" options:NSLayoutFormatAlignAllCenterX metrics:metrics views:constraintViews];
Try adding the line below:
[view1 setContentHuggingPriority:UILayoutPriorityHigh forAxis:UILayoutConstraintAxisHorizontal];
2) I always set the numberOfLines property of a label to 0 by default, so that the label will autoresize vertically if the text needs to be shown in two or more lines. That being said, you would need to remove the fixed height constraint and the label will be the size of the it's contents like so:
view1.numberOfLines = 0;
NSArray *vConstraints=[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-spacing-[view1]" options:0 metrics:metrics views:constraintViews];
I hope this helps.
I used this generic method for applying constraints of childView wrt to ParentView.Just pass your views to this method.
+ (void)applyConstraints:(UIView *)pChildView withSuperView:(UIView *)pParentView {
pChildView.translatesAutoresizingMaskIntoConstraints = NO;
// Width.
CGFloat widthValue = pParentView.frame.size.width;
[pParentView addConstraint:[NSLayoutConstraint constraintWithItem:pChildView attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual toItem:pParentView
attribute:NSLayoutAttributeWidth multiplier:1.0 constant:widthValue]];
// Height.
CGFloat heightValue = pParentView.frame.size.height;
[pParentView addConstraint:[NSLayoutConstraint constraintWithItem:pChildView attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual toItem:pParentView
attribute:NSLayoutAttributeHeight multiplier:1.0 constant:heightValue]];
// X margin.
[pParentView addConstraint:[NSLayoutConstraint constraintWithItem:pChildView attribute:NSLayoutAttributeCenterXWithinMargins
relatedBy:NSLayoutRelationEqual toItem:pParentView
attribute:NSLayoutAttributeCenterXWithinMargins multiplier:1.0 constant:0]];
// Y margin.
[pParentView addConstraint:[NSLayoutConstraint constraintWithItem:pChildView attribute:NSLayoutAttributeCenterYWithinMargins
relatedBy:NSLayoutRelationEqual toItem:pParentView
attribute:NSLayoutAttributeCenterYWithinMargins multiplier:1.0 constant:0]];
}

Autolayout "conflicting constraints"

I've created a custom UIView that I use modally to display a UIToolbar and UIPickerView. I'm trying to make it very reusable, so I'm creating all of the UI in code, including setting constraints.
Here's the method body I use to set the view up to be added to another view, and then to animate the controls up onto the view from the bottom.
My view hierarchy is as follows:
"Owner" view (view to which this view is added):<br>
|-->"Background" view (set to the full size of "Owner", but mainly used as a dimmed background)<br>
|-->"Container" view (view which holds the toolbar and picker)
|--> Toolbar
|--> Picker
Here's the code I use to set up the UI:
- (void)prepareForView:(UIView *)view {
UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
[containerView setTranslatesAutoresizingMaskIntoConstraints:NO];
self.containerView = containerView;
UIPickerView *picker = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, 162.0f)];
[picker setTranslatesAutoresizingMaskIntoConstraints:NO];
self.picker = picker;
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, 44.0f)];
[toolbar setTranslatesAutoresizingMaskIntoConstraints:NO];
UIBarButtonItem *done = ...;
UIBarButtonItem *flexSpace = ...;
UIBarButtonItem *cancel = ...;
toolbar.items = #[done, flexSpace, cancel];
[containerView addSubview:picker];
[containerView addSubview:toolbar];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[picker]|" options:NSLayoutFormatAlignAllBaseline metrics:nil views:NSDictionaryOfVariableBindings(picker)]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[toolbar]|" options:NSLayoutFormatAlignAllBaseline metrics:nil views:NSDictionaryOfVariableBindings(toolbar)]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[toolbar(==44)][picker(==162)]|" options:NSLayoutFormatAlignAllLeading metrics:nil views:NSDictionaryOfVariableBindings(toolbar, picker)]];
[containerView layoutIfNeeded];
[self addSubview:containerView];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[containerView]|" options:NSLayoutFormatAlignAllBaseline metrics:nil views:NSDictionaryOfVariableBindings(containerView)]];
self.containerTop = [NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:self.frame.size.height];
[self addConstraint:self.containerTop];
[self layoutIfNeeded];
}
Basically, I want containerView to be sized according to its contents (which should be a static 206 points). Then, I set a vertical space constraint between its top and the top of its superview (which is self). Later, I animate changing that so that the toolbar and picker "slide up" onto the screen.
Here's the animation code (the error is always triggered BEFORE this point):
// Add the view as a subview
[view addSubview:self];
// Setup view for display (here's what triggers the message)
[self prepareForView:view];
// Animate into view
[UIView animateWithDuration:animated?0.4f:0.0f
animations:^{
self.alpha = 1.0f;
}
completion:^(BOOL finished) {
// Now, slide the container view in from the bottom of the screen
self.containerTop.constant = self.frame.size.height - self.containerView.frame.size.height;
[UIView animateWithDuration:animated?0.4f:0.0f
animations:^{
[self layoutIfNeeded];
}
completion:^(BOOL finished) {
if (postDisplay != nil) {
postDisplay();
}
}
];
}
];
This is currently displaying correctly on all simulators and devices in testing, but I hate having warnings/errors, and I'm worried that this might NOT work as desired at some point.
Here's the actual error message that's displayed (I'm pretty sure this is exactly the same error every time):
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x170283430 V:|-(0)-[UIToolbar:0x137590850] (Names: '|':UIView:0x170382b10 )>",
"<NSLayoutConstraint:0x170283480 V:[UIToolbar:0x137590850(44)]>",
"<NSLayoutConstraint:0x174084ba0 V:[UIToolbar:0x137590850]-(0)-[UIPickerView:0x137586100]>",
"<NSLayoutConstraint:0x174081fe0 V:[UIPickerView:0x137586100(162)]>",
"<NSLayoutConstraint:0x17409bbc0 V:[UIPickerView:0x137586100]-(0)-| (Names: '|':UIView:0x170382b10 )>",
"<NSLayoutConstraint:0x174095b80 V:[UIView:0x170382b10(736)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x174084ba0 V:[UIToolbar:0x137590850]-(0)-[UIPickerView:0x137586100]>
What I don't understand is that all of the constraints ARE expected, and then the displayed UI is what I intend. When I inspect the view's layout with po [self.containerView recursiveDescription] in the debugger, I see the frames being exactly what I think they ought to be. Where am I going wrong?
The "Container" view appears to have a height of 736 from the line below:
<NSLayoutConstraint:0x174095b80 V:[UIView:0x170382b10(736)]>
You have laid out the view as below:
------ Top of UIView ------- (y = 0)
- 0 Space -
UIToolBar (y = 0 to y = 44)
- 0 Space -
UIPickerView (y = 44 to y = 206) ***
- 0 Space -
------ Bottom of UIView ----- (y = 736)
*** This is where the conflict arrises. This can't be 0 space away from the bottom of the UIView with all of the other constraints set the way that they are or the height of the UIView cannot be what it is with all of the other constraints.
EDIT:
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[containerView]|" options:NSLayoutFormatAlignAllBaseline metrics:nil views:NSDictionaryOfVariableBindings(containerView)]];
When you use "|" within a the visualFormat for a constraint this is the parent view. Within this line you are saying you want the parent view to 0 space to the top of the [containerView] and also 0 space from the bottom of the [containerView]. This makes the container view the same height as the parent.
Edit #2:
Look at the following. I believe this is close to what you are trying to accomplish.
[containerView addSubview:picker];
[containerView addSubview:toolbar];
[self addSubview:containerView];
// Height & Width for containerView
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"V:[containerView(%f)]", containerView.frame.size.height] options:nil metrics:nil views:#{#"containerView":containerView}]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:[containerView(%f)]", containerView.frame.size.width] options:nil metrics:nil views:#{#"containerView":containerView}]];
// Height & Width for picker
[picker addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"V:[picker(%f)]", picker.frame.size.height] options:nil metrics:nil views:#{#"picker":picker}]];
[picker addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:[picker(%f)]", picker.frame.size.width] options:nil metrics:nil views:#{#"picker":picker}]];
// Height & Width for toolbar
[toolbar addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"V:[toolbar(%f)]", toolbar.frame.size.height] options:nil metrics:nil views:#{#"toolbar":toolbar}]];
[toolbar addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:[toolbar(%f)]", toolbar.frame.size.width] options:nil metrics:nil views:#{#"toolbar":toolbar}]];
// Vertical Positioning of picker & toolbar in containerView
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[picker]" options:nil metrics:nil views:#{#"picker":picker}]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[toolbar]-0-|" options:nil metrics:nil views:#{#"toolbar":toolbar}]];
// Horizontal Positioning of picker & toolbar in containerView
[containerView addConstraint:[NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:picker attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
[containerView addConstraint:[NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:toolbar attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
// Center containerView (X/Y) in parent (self)
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
Edit #3: Using 'views' and 'metrics' dictionaries.
NSDictionary *views = #{#"containerView":containerView, #"picker":picker, #"toolbar":toolbar};
NSDictionary *metrics = #{#"hCV":containerView.frame.size.height,
#"wCV":containerView.frame.size.width,
#"hP":picker.frame.size.height,
#"wP":picker.frame.size.width,
#"hT":toolbar.frame.size.height,
#"wT":toolbar.frame.size.width};
[containerView addSubview:picker];
[containerView addSubview:toolbar];
[self addSubview:containerView];
// Height & Width for containerView
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[containerView(hCV)]" options:0 metrics:metrics views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[containerView(wCV)]" options:0 metrics:metrics views:views]];
// Height & Width for picker
[picker addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[picker(hP)]" options:0 metrics:metrics views:views]];
[picker addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[picker(wP)]" options:0 metrics:metrics views:views]];
// Height & Width for toolbar
[toolbar addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[toolbar(hT)]" options:0 metrics:metrics views:views]];
[toolbar addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[toolbar(wT)]" options:0 metrics:metrics views:views]];
// Vertical Positioning of picker & toolbar in containerView
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[picker]" options:0 metrics:nil views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[toolbar]-0-|" options:0 metrics:nil views:views]];
// Horizontal Positioning of picker & toolbar in containerView
[containerView addConstraint:[NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:picker attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
[containerView addConstraint:[NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:toolbar attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
// Center containerView (X/Y) in parent (self)
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];

Creating constraint to center label in view

I am trying to programatically setup some constraints. I have one container view UIView which holds three subviews.
UIView - circleView
UILabel - label1
UILabel - label2
The circleview is shown at the top of the container at (0,0,width,80). The label1 is shown underneath the circleview with 5.0 padding.
I am now trying to add the label2 to be in the center of the circleView. How do I do this with AutoLayout programatically.
This is what I currently do.
NSDictionary *views = NSDictionaryOfVariableBindings(circleView,labelView, iconLbl);
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[circleView(circleSize)]|" options:0 metrics:metrics views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[labelView]|" options:0 metrics:metrics views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[circleView(circleSize)]-(padding)-[labelView]-|" options:0 metrics:metrics views:views]];
The label2 is the iconLbl view in the dictionary.
This should be relatively straightforward - it helps to use xib to see how many constraints you actually need to get the effect you want. Constraining a label to be in the center of another view, both of which are in a parentView, only requires 2 constraints to be fully constrained. If this were a regular UIView, you'd need 4 constraints (x,y,width,height), but the label will automatically determine it's width and height from it's content, so it's not ambiguous. This is of course if you other views are all properly constrained, but you only asked about the label2 in the circle view.
I prefer to use the non-visual form for defining constraints because they read like mathematical equations. What you want is:
label2.centerX = circleView.centerX*1 + 0;
label2.centerY = circleView.centerY*1 + 0;
Since these are siblings with a common parent, the constraints are added to the parentView. So you get the following two constraints.
[parentView addConstraint:[NSLayoutConstraint constraintWithItem:label2 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:circleView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
[parentView addConstraint:[NSLayoutConstraint constraintWithItem:label2 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:circleView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
This is sufficient for getting label2 centered in the parentView. Any issues you get will likely be due to other constraints between your views not being properly specified.
Can you try this?
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[circleView(circleSize)]" options:0 metrics:metrics views:views]]; //Dont link to both the sides. Dock to the left edge
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self. labelView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0 ]]; //Specify the X
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self. labelView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0 ]]; //Specify Y
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[circleView(circleSize)]" options:0 metrics:metrics views:views]]; //Dock the circle to the top
With Masonry library
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(view);
}];

Aligning a UIImageView with Auto Layout

What I want is to add an image as a subview, then align it centered along the X axis and 10 points from the bottom of the superview. I need to use Auto Layout only, and preferably visual formatting language.
- (void)viewDidLoad
{
[super viewDidLoad];
self.imageView = [[UIImageView alloc] initWithFrame:CGRectZero];
[self.imageView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.imageView setImage:[UIImage imageNamed:#"06-arrow-south"]];
self.imageView.contentMode = UIViewContentModeScaleAspectFit;
[self.view addSubview:self.imageView];
[self addConstraints];
self.imageView.layer.borderColor = [[UIColor redColor] CGColor];
self.imageView.layer.borderWidth = 1.0;
}
- (void)addConstraints {
NSDictionary *viewsDictionary = #{#"arrowImage":self.imageView};
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[arrowImage(==40)]-|"
options:0
metrics:nil
views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[arrowImage(==40)]-10-|"
options:0
metrics:nil
views:viewsDictionary]];
}
Here's what I'm getting:
V:|-[arrowImage]-10-|
This aligns the image view so that it is the standard length (20pt) from the top of its superview, and 10 from the bottom. What you want is to PIN it to the bottom only:
V:[arrowImage]-10-|
I'm not sure that centering in the superview can be done with visual format, but you can create a single constraint to center it:
[self.view addConstraint:
[NSLayoutConstraint
constraintWithItem:self.imageView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
There's no need to set the height or width of the image view; its size will be determined from its content.
So, here's the full code for your addConstraints method:
- (void)addConstraints {
[self.view addConstraint:
[NSLayoutConstraint
constraintWithItem:self.imageView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
NSDictionary *viewsDictionary = #{#"arrowImage":self.imageView};
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[arrowImage]-10-|"
options:0
metrics:nil
views:viewsDictionary]];
}
What you currently doing is saying arrowImage should be the full size of the view minus 20px on left, right and top but be minus 10px from bottom.
The to center on x do the following.
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:arrowImage attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0];
Then as #Austin points out remove the need to be minus 8 from top and be minus 10 from the bottom:
V:[arrowImage]-10-|
Btw its minus 20 as default when you connect a sibling view to a parent: (see comment below )
|-[

UIView Awful Performance

I have built a slide navigation controller which allows the sliding of UIViewController's in a fast and smooth way (Facebook style). I have since added a UIViewController with a child view controller with it's own child view controller, as well as a table view. The lowest child view controller also has a view subviews. This UIViewController has the view that is made visible when the top view is slid away.
I have tested the smoothness both with and without this view controller. Without it the slide runs at a nice 60 frames per second, but with it my device is only managing a choppy 20 to 30 fps.
I have also tried removing subviews which seems to make a slight improvement, but not as much as I would expect. Even when switched out with another fairly complex view controller (without child view controls though) I get much better performance.
I am using auto layout throughout the app, and have come to believe this is the problem. None of my code is being executed whilst this poor sliding is occurring, so I believe it has something to do with the constraints being calculated as more of the view is being shown, but can't be sure.
As to avoid including the whole class, here are the updateViewConstraint methods in the view controller and subviews:
TOP VIEW CONTROLLER
/**
* Called when the view controller’s view needs to update its constraints.
*/
- (void)updateViewConstraints
{
[super updateViewConstraints];
// remove all constraints
[self.view removeConstraints:self.view.constraints];
NSArray *constraints;
// add the table view to the top of the view and the parameters view to the bottom
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(Panel)-[tableView]|"
options:kNilOptions
metrics:#{#"Panel": #(kPanelWidth)}
views:self.viewsDictionary];
[self.view addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[tableView]-|"
options:kNilOptions
metrics:nil
views:self.viewsDictionary];
[self.view addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(PanelPlus)-[recipeParameters]-|"
options:kNilOptions
metrics:#{#"PanelPlus": #(kPanelWidth + 20)}
views:self.viewsDictionary];
[self.view addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:[recipeParameters(==Height)]|"
options:kNilOptions
metrics:#{ #"Height" : #(kParametersControllerHeight)}
views:self.viewsDictionary];
[self.view addConstraints:constraints];
}
FIRST CHILD VIEW CONTROLLER
/**
* Called when the view controller’s view needs to update its constraints.
*/
- (void)updateViewConstraints
{
[super updateViewConstraints];
// remove all constraints
[self.view removeConstraints:self.view.constraints];
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[pageView]|" options:kNilOptions
metrics:nil views:self.viewsDictionary];
[self.view addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[pageView]|" options:kNilOptions
metrics:nil views:self.viewsDictionary];
[self.view addConstraints:constraints];
}
SECOND CHILD VIEW CONTROLLER
- (void)updateViewConstraints
{
[super updateViewConstraints];
NSArray *constraints;
// remove all constraints
[self.view removeConstraints:self.view.constraints];
if (self.interfaceOrientation == UIInterfaceOrientationPortrait || self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(8)-[optionLabel]-[selectionWheel]-[includeExclude(==32)]-|"
options:NSLayoutFormatAlignAllCenterX
metrics:nil
views:self.viewsDictionary];
[self.view addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[selectionWheel]-|"
options:kNilOptions
metrics:nil
views:self.viewsDictionary];
[self.view addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[includeExclude]-|"
options:kNilOptions
metrics:nil
views:self.viewsDictionary];
[self.view addConstraints:constraints];
}
else
{
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[selectionWheel]-|" options:kNilOptions
metrics:nil views:self.viewsDictionary];
[self.view addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[optionLabel]-[selectionWheel]-(Balance)-|"
options:NSLayoutFormatAlignAllCenterY
metrics:#{#"Balance": #(self.optionLabel.bounds.size.width + 40)}
views:self.viewsDictionary];
[self.view addConstraints:constraints];
}
}
CUSTOM UICONTROL (SUBVIEW OF SECOND CHILD VIEW CONTROLLER)
/**
* Update constraints for the view.
*/
- (void)updateConstraints
{
[super updateConstraints];
[self removeConstraints:self.constraints];
[self.excludeButton removeConstraints:self.excludeButton.constraints];
[self.includeButton removeConstraints:self.includeButton.constraints];
NSArray *constraints;
NSLayoutConstraint *constraint;
// add everything to fill the bounds
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(==6)-[excludeButton]-(==6)-|"
options:kNilOptions
metrics:nil
views:self.viewsDictionary];
[self addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[excludeButton][optionLabel][includeButton]|"
options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom
metrics:nil
views:self.viewsDictionary];
[self addConstraints:constraints];
// make the exclude and include buttons square
constraint = [NSLayoutConstraint constraintWithItem:self.excludeButton attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.excludeButton attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f];
[self.excludeButton addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:self.includeButton attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.includeButton attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f];
[self.includeButton addConstraint:constraint];
}
The implementation of the top UIViewController is here.

Resources