Adjusting subviews to keep their size using auto layout - objective-c

I have a UIView that contains subviews that looks like this:
This view was originally designed with 320 width in mind. iPhone 5s and lower. However I am now adapting it to work with iPhone 6+
The issue I am facing is getting the subviews width to grow to accommodate the extra space on the left and right of their super view. I can only seem to get the centre views width to grow, however not the out views. What constraints would I need to apply or change in order to get all views to grow a little to accommodate the extra space on the sides?

Hi!
If you design your view in interface builder, you may try this:
1- set all views to specific width and height
2- the view at the corner add pin to the edge with static value.
3- the view in the middle add pin to top or bottom, and add align constraint to horizontal centre of superview
Not sure if this help, Just try to answer!

Here is a complete example of how to achieve this programmatically (with dummy views):
// Simple example demonstrating the below screenshots
// Create containers to hold each row of subviews
UIView *container1 = [UIView new];
container1.translatesAutoresizingMaskIntoConstraints = NO;
container1.backgroundColor = [UIColor redColor];
UIView *container2 = [UIView new];
container2.translatesAutoresizingMaskIntoConstraints = NO;
container2.backgroundColor = [UIColor orangeColor];
// Create the subviews
UIView *v1 = [UIView new];
v1.translatesAutoresizingMaskIntoConstraints = NO;
v1.backgroundColor = [UIColor grayColor];
UIView *v2 = [UIView new];
v2.translatesAutoresizingMaskIntoConstraints = NO;
v2.backgroundColor = [UIColor blackColor];
UIView *v3 = [UIView new];
v3.translatesAutoresizingMaskIntoConstraints = NO;
v3.backgroundColor = [UIColor greenColor];
UIView *v4 = [UIView new];
v4.translatesAutoresizingMaskIntoConstraints = NO;
v4.backgroundColor = [UIColor purpleColor];
UIView *v5 = [UIView new];
v5.translatesAutoresizingMaskIntoConstraints = NO;
v5.backgroundColor = [UIColor blueColor];
UIView *v6 = [UIView new];
v6.translatesAutoresizingMaskIntoConstraints = NO;
v6.backgroundColor = [UIColor yellowColor];
// add the subviews
[container1 addSubview:v1];
[container1 addSubview:v2];
[container1 addSubview:v3];
[container2 addSubview:v4];
[container2 addSubview:v5];
[container2 addSubview:v6];
// Add the containers to the root view (in this case self.view)
[self.view addSubview:container1];
[self.view addSubview:container2];
// Add constraints for the containers
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[container1]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(container1)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[container2]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(container2)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-64.0-[container1(==100)]-[container2(==container1)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(container1, container2)]];
// Add constraints in both VFL and regular NSConstraints to the subviews of container 1
[container1 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[v1]-[v2(==v1)]-[v3(==v1)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(v1,v2,v3)]];
[container1 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[v1]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(v1)]];
[container1 addConstraint:[NSLayoutConstraint constraintWithItem:v2 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:v1 attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]];
[container1 addConstraint:[NSLayoutConstraint constraintWithItem:v2 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:container1 attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
[container1 addConstraint:[NSLayoutConstraint constraintWithItem:v3 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:v1 attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]];
[container1 addConstraint:[NSLayoutConstraint constraintWithItem:v3 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:container1 attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
// Add constraints in both VFL and regular NSConstraints to the subviews of container 2
[container2 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[v4]-[v5(==v4)]-[v6(==v4)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(v4,v5,v6)]];
[container2 addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[v4]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(v4)]];
[container2 addConstraint:[NSLayoutConstraint constraintWithItem:v5 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:v4 attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]];
[container2 addConstraint:[NSLayoutConstraint constraintWithItem:v5 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:container2 attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
[container2 addConstraint:[NSLayoutConstraint constraintWithItem:v6 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:v4 attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]];
[container2 addConstraint:[NSLayoutConstraint constraintWithItem:v6 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:container2 attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
Attached are screenshots on iPhone 5s, iPhone 6 and iPhone 6 Plus respectively:
iPhone 5s
iPhone 6
iPhone 6 Plus
I hope this at least point you in the right direction =)

disable autolayout and use autoresizing masks in the interface builderHandling Layout Changes Automatically Using Autoresizing Rules

Related

UIScrollView Not scrolling in iOS11

I have created a UIScrollView in code and it works in iOS10. I updated my Xcode today and it is no longer scrolling in iOS11 (simulator is iOS11 and does not work; physical iPad is still iOS10 and works).
User can add subviews when they want. When its the first subview, I anchor it to the left side, top and bottom of the scroll view. Then I anchor the right side of the subview to the right side of the scroll view which gives the contentSize its size and so it knows it needs to enable scrolling
UIScrollView *scrollViewMain = [UIScrollView new];
scrollViewMain.delegate = self;
scrollViewMain.backgroundColor = [UIColor greenColor];
scrollViewMain.translatesAutoresizingMaskIntoConstraints = NO;
scrollViewMain.directionalLockEnabled = YES;
self.scrollViewMain = scrollViewMain;
... // other code
if (self.countPlayers == 1) {
[self.scrollViewMain addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[playerCardView(400)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(playerCardView)]];
[self.scrollViewMain addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-20-[playerCardView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(playerCardView)]];
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.scrollViewMain attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:playerCardView attribute:NSLayoutAttributeRight multiplier:1 constant:10];
self.constraintScrollViewRight = constraint;
[self.scrollViewMain addConstraint:constraint];
}
else {
[self.scrollViewMain addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[previousPlayerCardView]-[playerCardView(==previousPlayerCardView)]" options:0 metrics:nil views:#{#"previousPlayerCardView": player.previousPlayer.playerViewCard, #"playerCardView": player.playerViewCard}]];
[self.scrollViewMain addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-20-[playerCardView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(playerCardView)]];
}
if (self.constraintScrollViewRight) {
[self.scrollViewMain removeConstraint:self.constraintScrollViewRight];
}
NSLayoutConstraint *constraintRight = [NSLayoutConstraint constraintWithItem:self.scrollViewMain attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:playerCardView attribute:NSLayoutAttributeRight multiplier:1 constant:10];
self.constraintScrollViewRight = constraintRight;
[self.scrollViewMain addConstraint:constraintRight];
[self.scrollViewMain layoutIfNeeded];
DLog(#"self.scrollViewMain: %#", self.scrollViewMain);
DLog(#"self.scrollViewMain.contentSize: %#", NSStringFromCGSize(self.scrollViewMain.contentSize));
The contentSize does become larger then the scroll view's frame:
2017-10-04 20:01:58.479446-0500 [ViewController addPlayer]_block_invoke [Line 242] self.scrollViewMain: <UIScrollView: 0x7fa9fd01b000; frame = (286 20; 462 1014); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x60000005ff20>; layer = <CALayer: 0x600000233580>; contentOffset: {0, 0}; contentSize: {826, 89}; adjustedContentInset: {0, 0, 0, 0}>
2017-10-04 20:01:58.479969-0500 [ViewController addPlayer]_block_invoke [Line 243] self.scrollViewMain.contentSize: {826, 89}
Why does iOS11 break my code?
EDIT:
Also, I try to scroll to the right to show the new subview when it appears:
[self.scrollViewMain scrollRectToVisible:playerCardView.frame animated:YES];
And it does nothing.
SOLUTION:
I changed
[self.scrollViewMain addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[playerCardView(200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(playerCardView)]];
To
[self.scrollViewMain addConstraint:[NSLayoutConstraint constraintWithItem:self.scrollViewMain attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:playerCardView attribute:NSLayoutAttributeLeft multiplier:1 constant:10]];
The UIScrollView now has a left and right anchor and can calculate its contentSize.
Kind of a crappy bug that the Visual Format is partially broken now.
Why does iOS11 break my code?
Because that is Apple's job.
Try creating all your constraints without using NSLayoutConstraint constraintsWithVisualFormat:
I've just had the exact same problem in my app on iOS 11, after upgrading to XCode 9.
After several hours of trying to find out what constraint caused the problems in my code, I happened to replace all calls to NSLayoutConstraint constraintsWithVisualFormat: with building the constraints "by code" using NSLayoutConstraint constraintWithItem: instead; and now it works as it's supposed to...
I guess Apple has modified the visual format analyzer in a way that causes some unexpected side effects...

Setting auto layout constraints programmatically on two views in ViewController

I am trying to add two UIView on ViewController. One of them is plain UIView and other is UITableView. I am not quite sure how to set height constraint on them in such away that UITableView will be of height required for its content and other view can resize itself based on UITableView height.
Below is the simple sketch and code I am using for setting up those constraints.
NSDictionary *views = NSDictionaryOfVariableBindings(_infoView,_infoTableView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"[_infoView]"
options:0
metrics:nil
views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[_infoView]-[_infoTableView]"
options:0
metrics:nil
views:views]];
// Width constraint
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.infoView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.infoTableView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.infoView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.infoTableView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0]];
Any comments / feedback would be highly appreciated.
Thanks.
You are on the right track. The trick here is that you need to dynamically update the height of tableView to its contentSize.height so infoView will know it should either be vertically expanded or shrunk:
First you define a property that will hold the height constraint:
#property (nonatomic, strong) NSLayoutConstraint *tableViewHeightConstraint;
- (void)viewDidLoad {
...
self.tableViewHeightConstraint = [NSLayoutConstraint constraintWithItem:self.tableView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.0
constant:350.0];
}
Then you can update the height constraint right after tableView knows its contentSize (ex: viewDidAppear:animated):
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.tableViewHeightConstraint.constant = self.tableView.contentSize.height;
[self.view layoutIfNeeded];
}
I created a sample project for you so you can play around with it to have a better understanding about what I intend to do.

Why doesn't contentView containing a label have any height in its scrollView in autolayout?

I'm creating a scrollView and adding a contentView to it using autolayout. The contentView's height I thought would be determined by the height and constraints of its contents. Since it has a label, shouldn't the contentView's height equal the label height? Only way height exists (in blue in the snapshot) is if adding a height constraint to the contentView. I thought this would be unnecessary since autolayout should know the heights of labels from their intrinsic content size?
.
// Scrollview
_scrollView = [UIScrollView new];
_scrollView.translatesAutoresizingMaskIntoConstraints = NO;
_scrollView.backgroundColor = [UIColor yellowColor];
_scrollView.bounces = YES;
[self.view addSubview:_scrollView];
NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_scrollView]|" options:0 metrics:0 views:#{ #"_scrollView" : _scrollView }];
NSArray *verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_scrollView]|" options:0 metrics:0 views:#{ #"_scrollView" : _scrollView }];
[self.view addConstraints:horizontalConstraints];
[self.view addConstraints:verticalConstraints];
// Content view
_contentView = [UIView new];
_contentView.translatesAutoresizingMaskIntoConstraints = NO;
_contentView.backgroundColor = [UIColor blueColor];
[_scrollView addSubview:_contentView];
NSArray *horizontalContentConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_contentView]|" options:0 metrics:0 views:#{ #"_contentView" : _contentView }];
NSArray *verticalContentConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_contentView]|" options:0 metrics:0 views:#{ #"_contentView" : _contentView }];
[_scrollView addConstraints:horizontalContentConstraints];
[_scrollView addConstraints:verticalContentConstraints];
// Why does height of content view need to be added to get the blue area to show?
NSLayoutConstraint *contentViewHeight = [NSLayoutConstraint constraintWithItem:_contentView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:NSLayoutAttributeNotAnAttribute attribute:NSLayoutAttributeHeight multiplier:1 constant:5];
[_contentView addConstraint:contentViewHeight];
NSLayoutConstraint *contentViewOuterLeading = [NSLayoutConstraint constraintWithItem:_contentView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1 constant:0];
NSLayoutConstraint *contentViewOuterTrailing = [NSLayoutConstraint constraintWithItem:_contentView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
[self.view addConstraints:#[ contentViewOuterLeading, contentViewOuterTrailing ]];
// Day label
_dayLabel = [UILabel new];
_dayLabel.translatesAutoresizingMaskIntoConstraints = NO;
_dayLabel.text = #"Monday";
_dayLabel.backgroundColor = [UIColor greenColor];
[_contentView addSubview:_dayLabel];
NSLayoutConstraint *dayLabelTop = [NSLayoutConstraint constraintWithItem:_dayLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:_contentView attribute:NSLayoutAttributeTop multiplier:1 constant:0];
NSLayoutConstraint *dayLabelCenterX = [NSLayoutConstraint constraintWithItem:_dayLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_contentView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
[_contentView addConstraints: #[ dayLabelTop, dayLabelCenterX ]];
It's because a UIScrollView has a content size of (0,0).
You can say it's bounds should be flush with the superview, but that's not actually changing its contentSize. Additionally, you add the contentView, but again you're saying it should be flush with its superview (the scrollview) though since the scroll view's size is still (0,0), you're implicitly saying that the content's view size will be 0,0. It's only after you add a constraint that specifically says 5px do you actually see a bit of the view.
A scroll view will get it's appropriate size from it's contents, so if you instantiated the content view as:
UIView * contentView = [[UIView alloc] initWithFrame:[UIScreen mainscreen].bounds];
The scroll view's content size would be equal to [UIScreen mainscreen].bounds and you would still be satisfying the layout constraints you write.
As you add UI elements to uiscrollview, and arrange them via layout constraints, the scrollview will automatically expand as needed.
I wrote a blog post exactly on this subject, Programmatic ScrollViews w/ NSLayout ... you may have too look at an older commit to it, but I ran into this exact same issue.
Ok figured it out. Adding a constraint from contentView to the bottom of its label made it work. No height constraint is needed for the contentView. Here's the updated code:
// Scrollview
_scrollView = [UIScrollView new];
_scrollView.translatesAutoresizingMaskIntoConstraints = NO;
_scrollView.backgroundColor = [UIColor yellowColor];
_scrollView.alwaysBounceVertical = YES;
[self.view addSubview:_scrollView];
NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_scrollView]|" options:0 metrics:0 views:#{ #"_scrollView" : _scrollView }];
NSArray *verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_scrollView]|" options:0 metrics:0 views:#{ #"_scrollView" : _scrollView }];
[self.view addConstraints:horizontalConstraints];
[self.view addConstraints:verticalConstraints];
// Content view
_contentView = [UIView new];
_contentView.translatesAutoresizingMaskIntoConstraints = NO;
_contentView.backgroundColor = [UIColor blueColor];
[_scrollView addSubview:_contentView];
NSArray *horizontalContentConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_contentView]|" options:0 metrics:0 views:#{ #"_contentView" : _contentView }];
NSArray *verticalContentConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[_contentView]|" options:0 metrics:0 views:#{ #"_contentView" : _contentView }];
[_scrollView addConstraints:horizontalContentConstraints];
[_scrollView addConstraints:verticalContentConstraints];
NSLayoutConstraint *contentViewOuterLeading = [NSLayoutConstraint constraintWithItem:_contentView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1 constant:0];
NSLayoutConstraint *contentViewOuterTrailing = [NSLayoutConstraint constraintWithItem:_contentView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
[self.view addConstraints:#[ contentViewOuterLeading, contentViewOuterTrailing ]];
// Day label
_dayLabel = [UILabel new];
_dayLabel.translatesAutoresizingMaskIntoConstraints = NO;
_dayLabel.text = #"Monday";
_dayLabel.backgroundColor = [UIColor greenColor];
[_contentView addSubview:_dayLabel];
NSLayoutConstraint *dayLabelTop = [NSLayoutConstraint constraintWithItem:_dayLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:_contentView attribute:NSLayoutAttributeTop multiplier:1 constant:0];
NSLayoutConstraint *dayLabelCenterX = [NSLayoutConstraint constraintWithItem:_dayLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_contentView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];
NSLayoutConstraint *dayLabelBottom = [NSLayoutConstraint constraintWithItem:_dayLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:_contentView attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
[_contentView addConstraints: #[ dayLabelTop, dayLabelCenterX, dayLabelBottom ]];

How to align UIImageView to the centre of the view controller?

I want an imageview to appear centre at the bottom,i added the imageview to another imageview in the view controller.the result is imageview is appearing at the bottom but not exactly at centre, can any one suggest what is wrong in my code?
-(void)viewWillAppear:(BOOL)animated
{
UIImageView *imgView=[[UIImageView alloc]init];
[imgView setTranslatesAutoresizingMaskIntoConstraints:NO];
UIImageView *mspimgvw=[[UIImageView alloc]init];
[mspimgvw setTranslatesAutoresizingMaskIntoConstraints:NO];
mspimgvw.image=[UIImage imageNamed:#"msplogo.jpg"];
[self.imgView addSubview:mspimgvw];
[self.view addSubview:imgView];
CGFloat bottom=0;
[imgView addConstraint:[NSLayoutConstraint constraintWithItem:mspimgvw attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:imgView attribute:NSLayoutAttributeBottom multiplier:1 constant:bottom-40]];
[imgView addConstraint:[NSLayoutConstraint constraintWithItem:mspimgvw attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:imgView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:bottom-40]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[imgView]|" options:0 metrics: 0 views:dicViews]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[imgView]|" options:0 metrics: 0 views:dicViews]];
}
I want image to appear to the centre of the view controller.What to change in my code?
Here you go:
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:imageView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.f
constant:0.f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:imageView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.f
constant:0.f]];

Autolayout when adding subview to UIWindow

I am creating a customalertview that needs to be added as a subview to UIWindow. I've setup the constraints for it's subviews correctly but I'm confused as to when/how to set the constraints on the view itself in relation to the window.
I would like the width of the alertview to be 70% of the width of the screen. The height is already in relation to it's subviews.
- (void)show {
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
[window addSubview:self];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:[UIApplication sharedApplication].keyWindow attribute:NSLayoutAttributeWidth multiplier:0.7 constant:0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:_messageLabel attribute:NSLayoutAttributeBottom multiplier:1.0 constant:10]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:(_imageView.image ? _imageView : _titleLabel) attribute:NSLayoutAttributeTop multiplier:1.0 constant:-10]];
}
What am I doing wrong? I am getting the following error message:
NSLayoutConstraint:0x181cd7c0 WFSoftAlertView:0x16e384c0.width == 0.7*UIWindow:0x16e7c8c0.width>
When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled.
WFSoftAlertView.translatesAutoresizingMaskIntoConstraints=NO;
NSDictionary *views = NSDictionaryOfVariableBindings(WFSoftAlertView);
float width30 = self.view.frame.size.width*.3;
width30 = width30/2; // divided by 2 for padding of its left/rigth
NSString *str =[NSString stringWithFormat:#"%f",width30];
NSDictionary *metrics = #{#"width":str};
[self.view addSubview:WFSoftAlertView];
//add the WFSoftAlertView in center(x) of superview with a padding of "width"
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|-width-[WFSoftAlertView]-width-|" options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:metrics views:views]];
// if you want center(y)
NSLayoutConstraint *centerY = [NSLayoutConstraint
constraintWithItem:WFSoftAlertView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:0.f];
Try changing your constraintWithItem from
self
to
self.view