I am using Auto Layout. I have a view with a subview (sb1). I am programmatically adding another subview (sb2) to this view. I am adding constraints to this new subview.
What I want accomplish:
add sb2 below sb1 an add a constraint to the top of sb2 to pin it to sb1.
What I've tried:
[self.containerView insertSubview:sb1
belowSubview:sb2];
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:sb1
attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
toItem:sb2 attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.f];
[self.otherLeftView addConstraint:constraint];
What is happening is my newly added subview is being pinned to the top of the container view, NOT to the sb1 (which is what I want to happen). Visual of what is happening:
Does anyone know how I can add a constraint between SB1 and SB2? Thanks!
Try this:
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:sb1
attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual
toItem:sb2 attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.f];
Related
I am trying to create the following setup with Autolayout to my UITableView before I add it as a subview of its wrapper UIView.
I am using the following so far but haven't had any luck at all. This is as far as I have got and it is throwing an errors.
//Trailing
NSLayoutConstraint *trailing =[NSLayoutConstraint
constraintWithItem:self.tableViewVideoList
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.viewContentWrapper
attribute:NSLayoutAttributeTrailing
multiplier:1.0f
constant:0.f];
//Leading
NSLayoutConstraint *leading = [NSLayoutConstraint
constraintWithItem:self.tableViewVideoList
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.viewContentWrapper
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:0.f];
//Bottom
NSLayoutConstraint *bottom =[NSLayoutConstraint
constraintWithItem:self.tableViewVideoList
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.viewContentWrapper
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.f];
[self.viewContentWrapper addConstraint:trailing];
[self.viewContentWrapper addConstraint:bottom];
[self.viewContentWrapper addConstraint:leading];
[self.viewContentWrapper addSubview:self.tableViewVideoList];
Any help would be great thanks, I usually do all the Autolayout work in the Storybaord.
You probably forgot to do this:
self.tableViewVideoList.translatesAutoresizingMaskIntoConstraints = NO;
And you should add `tableViewVideoList' to its superview before setting the constraints.
And you are missing a top layout constraint or height constraint (as 3stud1ant3 pointed out)
I put an CustomView in UITableViewCell.contentView, setting the autoresize mask of the custom view as W+H.
But when running, the CustomView gets a larger height than the ContentView, the ContentView is 60pt in height(which is the same as setting in UITableViewDelegate), but the CustomView inside contentView is 76pt in height.
By Xcode6's view debugging, I see some strange constraints on my custom view, they are:
self.height = superview.height + 16
self.midY = superview.midY + 8
Where are these constraints come from and how to modify them? I've never set anything with a value 8 or 16.
UPDATE:
I've made a test project, which is simply a tableview in storyboard with a CustomView loaded from a nib file, and this test project replicated the problem, when running, the CustomView which is a subview of TableViewCell.contentView becomes larger in height than the TableViewCell.contentView.
The test project is here:
https://drive.google.com/file/d/0B5y_NrRbhGlSb1dlbVZNb19vNjQ/view?usp=sharing
At last I understand, auto layout can only form relations in the same xib or storyboard, my CustomView is in a separated xib and is loaded at runtime, so the super view and CustomView don't have any auto layout constraints between them.
If I set translatesAutoresizingMaskIntoConstraints to YES, then there goes the problem, I still don't know why using W+H as auto resizing mask makes CustomView taller than its super view(cell.contentView), but I found a way around:
I manually add constraints between superview and CustomView, and turn off customView. translatesAutoresizingMaskIntoConstraints, there the code goes:
customView.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:customView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:cell.contentView attribute:NSLayoutAttributeTop multiplier:1 constant:0];
NSLayoutConstraint *bottom = [NSLayoutConstraint constraintWithItem:customView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:cell.contentView attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:customView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:cell.contentView attribute:NSLayoutAttributeLeft multiplier:1 constant:0];
NSLayoutConstraint *right = [NSLayoutConstraint constraintWithItem:customView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:cell.contentView attribute:NSLayoutAttributeRight multiplier:1 constant:0];
[cell.contentView addConstraints:#[top, bottom, left, right]];
I have a UICollectionView added to a UIView. I just want the collection view to resize with orientation change, so that it fits the superview (UIView). After I add the layout constraint the collection view is missing. I could not even get the first constraint work properly.(below)
NSLayoutConstraint *leftSideConstraint = [NSLayoutConstraint constraintWithItem:self.collectionView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:10.0];
And then I add the constraint to self.view.
What am I doing wrong? Please, help!
Update:
This is how it works. I am new to autolayouts. I was just trying to satisfy the constraints one by one to be sure that they all work:) Thank you
NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:self.collectionView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:5.0];
NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:self.collectionView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:-5.0];
NSLayoutConstraint *constraint3 = [NSLayoutConstraint constraintWithItem:self.collectionView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-5.0];
NSLayoutConstraint *constraint4 = [NSLayoutConstraint constraintWithItem:self.collectionView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:5.0];
[self.view addConstraints:#[constraint1, constraint2, constraint3, constraint4]];
You can't just add one constraint for view to position correctly. It needs to know it's x and y position, width and height. With this one constraint you only gave it x position. You need three more constraints eg. trailing, top and bottom or top, width, height. Basically any set of constraints that will fully describe view position, width and height.
I have a view(self.printSettingsView) created from xib. I add this view as a subview to another view(self.view). I programmatically add constraints as follows:
[self.printSettingView setTranslatesAutoresizingMaskIntoConstraints: NO];
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:self.printSettingView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0];
[self.view addConstraint:leftConstraint];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.printSettingView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.topBar
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0];
[self.view addConstraint:topConstraint];
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self.printSettingView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0];
[self.view addConstraint:heightConstraint];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self.printSettingView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0];
[self.view addConstraint:widthConstraint];
All the other constraints take effect except for height.
What could i be doing wrong here???
Thanks
Without knowing the constraints on your xib file or what you expect to happen vs what is happening (a screenshot would be helpful) it's hard to say. However I do have one suggestion where maybe the logic isn't correct.
The second constraint is pinning printViewSettings top to the bottom of the topBar, that part makes sense. The next one however sets the height of printViewSettings to the height of its superview. This may not jive with what you want because your superview contains your topBar as well and so may be larger than you expect. What you might actually want is a constraint that pins the bottom of printViewSettings to the bottom of the superview instead.
Sorry guys about the incomplete information. The problem in a gist was that i was assigning a constraint to the subview in my main view and whatever be the constant of the constraint the size of the subview remained constant. I found that the issue was the subview in turn had components(subviews) with fixed height constraints. I made them proportional to the height of the parent view and it works now.
I tried to write a category function for UIView that will get the constraints that will hold an given frame in place in its superview. I implemented it like so:
-(NSArray *)constraintsForLockingPositionInSuperview
{
NSLayoutConstraint *left=[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.superview
attribute:NSLayoutAttributeLeft multiplier:0 constant:self.frame.origin.x];
NSLayoutConstraint *height=[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:Nil
attribute:NSLayoutAttributeNotAnAttribute multiplier:0 constant:self.frame.size.height];
NSLayoutConstraint *width=[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:Nil
attribute:NSLayoutAttributeNotAnAttribute multiplier:0 constant:self.frame.size.width];
NSLayoutConstraint *top=[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.superview
attribute:NSLayoutAttributeTop multiplier:0 constant:self.frame.origin.y];
return #[left,height,width,top ];
}
And then after animating the view, apply to new constraints by doing the following in the view controller that contains the view in question. I remove the view then re-add it to remove the constraints that were on it, then reapply the new constraints. The hope was that this would hold the view in place if I add another subview or if something like an actionView comes in and the view has to layout itself out. The height and the width seem to be locking properly, but the view is jumping to the middle instead of locking in place:
NSArray *lockingConstraints = [someView constraintsForLockingPositionInSuperview];
[someView removeFromSuperview];
[self.view addSubview:someView;
[self.view addConstraints:lockingConstraints];
[self.view layoutSubviews];
From the documentation for layoutSubviews:
You should not call this method directly.
Call layoutIfNeeded instead.