iOS: Visual format constraints are broken - ios

I'm trying to lay a button over a map and constrain it to 10 points in from the left and 10 points up from the bottom. However, when I run it in simulator it tells me my constraints are broken. Here's my code. What am I missing?
_map = [[MKMapView alloc] init];
[self setView:_map];
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(39.810166, -86.156708);
_loc = [[TCMLocationPoint alloc] initWithCoordinate:coord title:#"My Location" subtitle:#"My Subtitle"];
[_loc setParent:_map];
[_map addAnnotation:_loc];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coord, 2000, 2000);
[_map setRegion:region animated:NO];
_directionsButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_directionsButton addTarget:self action:#selector(getLocation:) forControlEvents:UIControlEventTouchDown];
[_directionsButton setTitle:#"Get Directions" forState:UIControlStateNormal];
[_directionsButton setFrame:CGRectMake(0.0, 0.0, 150.0, 25.0)];
[[self view] addSubview:_directionsButton];
NSDictionary *nameMap = #{#"button" : _directionsButton};
NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-10-[button]-(>=0)-|"
options:0
metrics:nil
views:nameMap];
[[self view] addConstraints:horizontalConstraints];
NSArray *verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(>=0)-[button]-10-|"
options:0
metrics:nil
views:nameMap];
[[self view] addConstraints:verticalConstraints];

A couple of thoughts:
I'd set translatesAutoresizingMaskIntoConstraints to NO.
You can probably simplify your VFL, too, and eliminate the >=0 stuff. You can also set the width and height right in your VFL.
You also don't need to set the frame. Let the constraints set the width, height.
Unless you're doing this in loadView, I'd suggest you add the map as a subview rather than trying to set self.view.
Thus:
_map = [[MKMapView alloc] init];
_map.delegate = self; // if you've implemented any `MKMapViewDelegate` methods, you should set your delegate
[_map setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:_map];
NSDictionary *views = #{#"map" : _map};
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[map]|"
options:0
metrics:nil
views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[map]|"
options:0
metrics:nil
views:views]];
// do your stuff where you're adding your annotation here
_directionsButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_directionsButton addTarget:self action:#selector(getLocation:) forControlEvents:UIControlEventTouchDown];
[_directionsButton setTitle:#"Get Directions" forState:UIControlStateNormal];
[_directionsButton setTranslatesAutoresizingMaskIntoConstraints:NO];
[[self view] addSubview:_directionsButton];
NSDictionary *nameMap = #{#"button" : _directionsButton};
NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-10-[button(150)]"
options:0
metrics:nil
views:nameMap];
[[self view] addConstraints:horizontalConstraints];
NSArray *verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:[button(25)]-10-|"
options:0
metrics:nil
views:nameMap];
[[self view] addConstraints:verticalConstraints];
You might even want to set the priority for the width and height constraints to be less than 1000, that way if the font dictates that the button should be a little larger, you'll let it grow, e.g. #"H:|-10-[button(150#500)]" and #"V:[button(25#500)]-10-|".

Related

Vertical scrolling not working UIScrollView programatically

I am not sure what is wrong with my code. I have embedded UIView inside the UIScrollView. There are some controls which have been embedded inside this UIView. I am expecting the scrolling to happen for the UIView but it does not. Eventually I am unable to view all the controls. I am just pasting my code below. Appreciate if somebody points out what I am missing here.
UIView *parentView = [[UIView alloc]init];
[parentView setTranslatesAutoresizingMaskIntoConstraints:NO];
parentView.backgroundColor = [UIColor whiteColor];
[self.view addSubview: parentView];
NSArray *parentViewHConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:[parentView(==mainView)]" options:0 metrics:0 views:#{#"parentView": parentView, #"mainView":self.view}];
NSArray *parentViewVConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-10-[parentView]-10-|" options:0 metrics:0 views:#{#"parentView": parentView}];
[self.view addConstraints:parentViewHConstraints];
[self.view addConstraints:parentViewVConstraints];
self.myScrollView = [[UIScrollView alloc] init];
//CGSize scrollableSize = CGSizeMake(100, 200);
//[self.myScrollView setContentSize:scrollableSize];
[parentView addSubview:self.myScrollView];
self.myScrollView.backgroundColor = [UIColor lightGrayColor];
self.myScrollView.translatesAutoresizingMaskIntoConstraints = NO;
NSArray *scrollViewHContraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[scrollView]|" options:0 metrics:0 views:#{#"scrollView": self.myScrollView}];
[parentView addConstraints:scrollViewHContraints];
UIView *contentView = [[UIView alloc]init];
contentView.translatesAutoresizingMaskIntoConstraints = NO;
[self.myScrollView addSubview:contentView];
self.myScrollView.showsVerticalScrollIndicator = YES;
self.myScrollView.pagingEnabled = YES;
self.myScrollView.contentSize = CGSizeMake(510,221);
NSArray *contentViewHConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[contentview(==scrollView)]|" options:0 metrics:nil views:#{#"contentview": contentView,#"scrollView": self.myScrollView}];
NSArray *contentViewVConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[contentview(==scrollView)]|" options:0 metrics:nil views:#{#"contentview": contentView,#"scrollView": self.myScrollView}];
[self.myScrollView addConstraints:contentViewHConstraints];
[self.myScrollView addConstraints:contentViewVConstraints];
UIFont *headingFont = [UIFont fontWithName:#"Helvetica Neue" size:40];
self.m_ObjTopHeadingLbl = [[UILabel alloc]init];
[self.m_ObjTopHeadingLbl setText:#"Registration"];
self.m_ObjTopHeadingLbl.font = headingFont;
[self.m_ObjTopHeadingLbl setTextColor:[UIColor redColor]];
self.m_ObjTopHeadingLbl.translatesAutoresizingMaskIntoConstraints = NO;
[contentView addSubview:self.m_ObjTopHeadingLbl];
NSArray *topHeadingHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[registView]-|" options:0 metrics:nil views:#{#"registView": self.m_ObjTopHeadingLbl}];
[contentView addConstraints:topHeadingHorzConstraint];
// Name field
self.m_ObjNameField = [[JVFloatLabeledTextField alloc]init];
self.m_ObjNameField.borderStyle = UITextBorderStyleRoundedRect;
self.m_ObjNameField.translatesAutoresizingMaskIntoConstraints = NO;
self.m_ObjNameField.placeholder = [NSString stringWithFormat:#"Enter your short name"];
[contentView addSubview:self.m_ObjNameField];
NSArray *nameFieldHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[nameFieldView]-|" options:0 metrics:nil views:#{#"nameFieldView": self.m_ObjNameField}];
[contentView addConstraints:nameFieldHorzConstraint];
// Info on the name field
UILabel* nameFieldLbl = [[UILabel alloc]init];
[nameFieldLbl setText:#"Will be visible to all on ipomo"];
UIFont *nameFieldLblFont = [UIFont fontWithName:#"Arial-BoldMT" size:13];
[nameFieldLbl setFont:nameFieldLblFont];
[nameFieldLbl setTextColor:[UIColor grayColor]];
nameFieldLbl.translatesAutoresizingMaskIntoConstraints = NO;
[contentView addSubview:nameFieldLbl];
NSArray *nameFieldlblHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[nameFieldLbl]-|" options:0 metrics:nil views:#{#"nameFieldLbl": nameFieldLbl}];
[contentView addConstraints:nameFieldlblHorzConstraint];
// Mobilenumber field
self.m_ObjMobNo = [[JVFloatLabeledTextField alloc]init];
self.m_ObjMobNo.borderStyle = UITextBorderStyleRoundedRect;
self.m_ObjMobNo.translatesAutoresizingMaskIntoConstraints = NO;
self.m_ObjMobNo.placeholder = [NSString stringWithFormat:#"Enter your mobilenumber"];
[contentView addSubview:self.m_ObjMobNo];
NSArray *mobnoFieldHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[mobnoField]-|" options:0 metrics:nil views:#{#"mobnoField": self.m_ObjMobNo}];
[contentView addConstraints:mobnoFieldHorzConstraint];
// Info on the mobile number field
UILabel* mobnoFieldLbl = [[UILabel alloc]init];
[mobnoFieldLbl setText:#"To send you the activation code. Hidden and secure"];
dispatch_async(dispatch_get_main_queue(), ^{
mobnoFieldLbl.preferredMaxLayoutWidth = self.view.bounds.size.width;
});
UIFont *mobnoFieldLblFont = [UIFont fontWithName:#"Arial-BoldMT" size:13];
[mobnoFieldLbl setFont:mobnoFieldLblFont];
mobnoFieldLbl.numberOfLines = 0;
[mobnoFieldLbl setTextColor:[UIColor grayColor]];
mobnoFieldLbl.translatesAutoresizingMaskIntoConstraints = NO;
[contentView addSubview:mobnoFieldLbl];
NSArray *mobnoFieldlblHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[mobnoFieldlbl]-|" options:0 metrics:nil views:#{#"mobnoFieldlbl": mobnoFieldLbl}];
[contentView addConstraints:mobnoFieldlblHorzConstraint];
// Email id field
self.m_ObjEmailId = [[JVFloatLabeledTextField alloc]init];
self.m_ObjEmailId.borderStyle = UITextBorderStyleRoundedRect;
self.m_ObjEmailId.translatesAutoresizingMaskIntoConstraints = NO;
self.m_ObjEmailId.placeholder = [NSString stringWithFormat:#"Enter your email id"];
[contentView addSubview:self.m_ObjEmailId];
NSArray *emailFieldHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[emailField]-|" options:0 metrics:nil views:#{#"emailField": self.m_ObjEmailId}];
[contentView addConstraints:emailFieldHorzConstraint];
// Info on the email field
UILabel* emailFieldLbl = [[UILabel alloc]init];
[emailFieldLbl setText:#"To send analytics and reports on happenings in you room(s). Hidden and secure"];
emailFieldLbl.numberOfLines = 0;
UIFont *emailFieldLblFont = [UIFont fontWithName:#"Arial-BoldMT" size:13];
dispatch_async(dispatch_get_main_queue(), ^{
emailFieldLbl.preferredMaxLayoutWidth = self.view.bounds.size.width;
});
[emailFieldLbl setFont:emailFieldLblFont];
[emailFieldLbl setTextColor:[UIColor grayColor]];
emailFieldLbl.translatesAutoresizingMaskIntoConstraints = NO;
[contentView addSubview:emailFieldLbl];
NSArray *emailFieldlblHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[emailFieldlbl]-|" options:0 metrics:nil views:#{#"emailFieldlbl": emailFieldLbl}];
[contentView addConstraints:emailFieldlblHorzConstraint];
// Promo code field
self.m_ObjPromoCode = [[JVFloatLabeledTextField alloc]init];
self.m_ObjPromoCode.borderStyle = UITextBorderStyleRoundedRect;
self.m_ObjPromoCode.translatesAutoresizingMaskIntoConstraints = NO;
self.m_ObjPromoCode.placeholder = [NSString stringWithFormat:#"Enter promocode (if applicable)"];
[contentView addSubview:self.m_ObjPromoCode];
NSArray *promocodeFieldHorzConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[promocodeField]-|" options:0 metrics:nil views:#{#"promocodeField": self.m_ObjPromoCode}];
[contentView addConstraints:promocodeFieldHorzConstraint];
// Submit button
self.m_ObjSubmitBut = [[UIButton alloc]init];
[self.m_ObjSubmitBut setTitle: [NSString stringWithFormat:#"SUBMIT"] forState:UIControlStateNormal];
self.m_ObjSubmitBut.backgroundColor = [UIColor redColor];
[self.m_ObjSubmitBut setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
self.m_ObjSubmitBut.translatesAutoresizingMaskIntoConstraints = NO;
self.m_ObjSubmitBut.layer.cornerRadius = 10;
self.m_ObjSubmitBut.clipsToBounds = YES;
[parentView addSubview:self.m_ObjSubmitBut];
NSDictionary *myTopViews = #{
#"scrollView": self.myScrollView,
#"submitButton": self.m_ObjSubmitBut,
};
NSArray *myTopVConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[scrollView]-[submitButton(40)]|" options:0 metrics:nil views:myTopViews];
NSArray *myTopHConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[submitButton]-|" options:0 metrics:nil views:#{#"submitButton": self.m_ObjSubmitBut}];
[parentView addConstraints:myTopVConstraints];
[parentView addConstraints:myTopHConstraints];
NSDictionary* myViews = #{
#"registView": self.m_ObjTopHeadingLbl,
#"nameView": self.m_ObjNameField,
#"nameFieldLbl": nameFieldLbl,
#"mobnoView":self.m_ObjMobNo,
#"mobnoFieldLbl":mobnoFieldLbl,
#"emailView":self.m_ObjEmailId,
#"emailFieldLbl":emailFieldLbl,
#"promocodeView":self.m_ObjPromoCode
};
NSDictionary* myMetrics = #{
#"sepHeight" : #30.0f,
#"sepHeight1" : #5.0f
};
NSArray *otherConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:[registView]-sepHeight-[nameView]-sepHeight1-[nameFieldLbl]-sepHeight-[mobnoView]-sepHeight1-[mobnoFieldLbl]-sepHeight-[emailView]-sepHeight1-[emailFieldLbl]-sepHeight-[promocodeView]" options:0 metrics:myMetrics views:myViews];
[contentView addConstraints:otherConstraints];
You're setting the size of your contentview to be equal to the size of the containing scrollview. Logically this means the scrollview has no area to scroll to and therefore will be fixed. You need to make the contentview longer (for vertical scrolling) or wider (for horizontal scrolling).
I think you are missing to mention scrollEnabled of UIScrollView, try following line and hope it works for you.
scrollView.scrollEnabled = YES;
Also set contentSize and its size should be greater than size of containing window to allow it to be scrollable.
[self.scrollforImage setContentSize:CGSizeMake(3000, 3000)];// replace 3000, 3000 according to your need
The constraints for the scrollview in your code are not sufficient. When using auto-layout, ensure that a proper chain of constraints are added in the vertical and horizontal directions.
For a scroll view to scroll, these are some general guidelines,
Ensure all the different sections of the UI have sufficient number of vertical and horizontal constraints. Take a simple UILabel in the screen. It needs a x,y position - can be a leading/top, centre attribute and it needs a size definition - either fixed width and height or a constraint with the nearby elements. It needs the position - size combination clearly defined for it to be managed by auto-layout.
If you set the translatesAutoresizingMaskIntoConstraints to NO, what you are saying is that the component shouldn't take the frame,size already set to be constraint requirements. If you want to explicitly mention frame or size for some elements, leave this as YES.
If the contentview is pinned in all four sides to the scrollview and the scrollview has its size,position defined as constraints or frame, it will be enough to make the content scrollable.
If the content size of the contentview changes dynamically during different events, you can set the scrollview.contentsize to the contentview.width and contentview.height explicitly.
Also, check this, a technical note from Apple on AutoLayout and Scrollviews.

Align UIButtons horizontally using Auto layout (programmatically)

I'm trying to place 2 UIButtons horizontally but no luck
I'm using auto layout constraints programmatically.
I don't want to put them in a container and align center to that container.
NSDictionary *metrics = #{#"kLeftPadding":#(kLeftPadding),
#"kRightPadding":#(kRightPadding),
#"kMiddlePadding":#(kMiddlePadding),
#"kBottomPadding":#(kBottomPadding)};
NSDictionary *constrainedViews = #{#"titleLabel": self.titleLabel,
#"btnToday" : self.btnToday,
#"btnPickaDay" : self.btnPickaDay,
#"dividerView" : dividerView};
NSArray *contraints = #[#"V:|-[titleLabel]-kBottomPadding-[btnToday(==40)]-[btnPickaDay(==btnToday)]-kBottomPadding-[dividerView]-0-|",
#"H:|-kLeftPadding-[titleLabel]-|",
#"H:|-kLeftPadding-[btnToday]-kMiddlePadding-[btnPickaDay(==btnToday)]-kRightPadding-|",
#"H:|-0-[dividerView]-0-|"];
second button starts from where first ends but in next line, not on same.
I've tried your code but it's getting crashed so as per your question you simply need to write below code.
UILabel *lblText = [UILabel new];
[lblText setText:#"Some Title Text"];
[lblText setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:lblText];
UIButton *btnRed = [UIButton new];
[btnRed setBackgroundColor:[UIColor redColor]];
[btnRed setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:btnRed];
UIButton *btnGreen = [UIButton new];
[btnGreen setBackgroundColor:[UIColor greenColor]];
[btnGreen setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:btnGreen];
UIView *vwLine = [UIView new];
[vwLine setBackgroundColor:[UIColor blueColor]];
[vwLine setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:vwLine];
NSDictionary *dictViews = #{#"red":btnRed,#"green":btnGreen,
#"line":vwLine,#"lbl":lblText};
NSDictionary *dictMetrics = #{#"height":#(40),#"offset":#(-40)};
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-20-[red]-0-[green(==red)]-20-|" options:0 metrics:nil views:dictViews]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-20-[line]-20-|" options:0 metrics:nil views:dictViews]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-20-[lbl]-20-|" options:0 metrics:nil views:dictViews]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(height)-[lbl]-(height)-[red(height)]-(offset)-[green(==red)]-50-[line(2)]" options:0 metrics:dictMetrics views:dictViews]];
result:
Hope it will help you solve your problem. If any more query do let me know.

Why are items outside the view?

I had two buttons in a UIView, then I add the view to main view, but I eventually got something like this:
As you can see these two buttons went outside the red view.
I wanted a little bit of margin on top, so I use constraintsWithVisualFormat:#"V:|-100-[buttonGroup]-10-|", I'm not sure if that matters.
Here's the original code:
- (UIButton*) getButtonWithTitle: (NSString*) title
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
button.layer.borderColor = [UIColor blackColor].CGColor;
button.layer.borderWidth = 0.5f;
button.layer.cornerRadius = 2.0f;
[button setTranslatesAutoresizingMaskIntoConstraints:NO];
[button setTitle:title forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState: UIControlStateNormal];
return button;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.view setTranslatesAutoresizingMaskIntoConstraints:NO];
UIButton *loginBtn = [self getButtonWithTitle:#"Login"];
UIButton *registerBtn = [self getButtonWithTitle:#"Register"];
UIView *buttonGroup = [[UIView alloc] init];
[buttonGroup setTranslatesAutoresizingMaskIntoConstraints:NO];
[buttonGroup addSubview: loginBtn];
[buttonGroup addSubview: registerBtn];
[self.view addSubview: buttonGroup];
[buttonGroup setBackgroundColor:[UIColor redColor]];
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(loginBtn, registerBtn, buttonGroup);
[buttonGroup addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[loginBtn]-20-[registerBtn(==loginBtn)]-|"
options:0
metrics:nil
views:viewsDictionary
]];
NSArray *verticalConstraints = [NSLayoutConstraint
constraintsWithVisualFormat:#"V:|-100-[buttonGroup]-10-|"
options:0
metrics:nil
views:viewsDictionary];
NSArray *horizontalConstraints = [NSLayoutConstraint
constraintsWithVisualFormat:#"H:|-[buttonGroup]-|"
options:0
metrics:nil
views:viewsDictionary];
[self.view addConstraints: horizontalConstraints];
[self.view addConstraints: verticalConstraints];
}
EDIT
The constraints I added:
[buttonGroup addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[loginBtn]-|"
options:0
metrics:nil
views:viewsDictionary
]];
[buttonGroup addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[registerBtn]-|"
options:0
metrics:nil
views:viewsDictionary
]];
It looks like I did extra work ...
You never created any vertical constraints between the buttons and buttonGroup; add those, and you should be good. Also, you shouldn't set translatesAutoresizingMaskIntoConstraints to NO for the controller's self.view (only for subviews that you add to it).
In the VFL , the | means the superview, but your two buttons(loginBtn, registerBtn) are the subviews of the buttonGroup. So you should define the V relation about the loginBtn, registerBtn with the buttonGroup. As rdelmar said, the self.view should set the translatesAutoresizingMaskIntoConstraints to No. This can close the autosizingmask function. I think the best way to do this things in xib or storyboard.

How to add constraints programatically to place a label at the left bottom of the screen?

I want to place a label at the bottom left of the screen: So I added the following code:
UILabel *versionLabel = [UILabel new];
versionLabel.text = #"some text";
versionLabel.textColor = [UIColor whiteColor];
versionLabel.font = [UIFont systemFontOfSize:10.0];
[self.view addSubview:versionLabel];
[versionLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
NSDictionary *views = NSDictionaryOfVariableBindings(versionLabel);
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"H:|-3-[versionLabel]"
options:0
metrics:nil
views:views]];
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:#"V:[versionLabel]-3-|"
options:0
metrics:nil
views:views]];
My issue is that the label ends up at the top left always. No way to move it at the bottom when I add constraints.
If you wrap the UITableViewController in a UIViewController, you can layout the label and table view as you see fit.
#import "WrappingViewController.h"
#import "YourCustomTableViewController.h"
#implementation WrappingViewController {
}
- (void)viewDidLoad {
// I instantiate this manually, but you could use an outlet from interface builder
UITableViewController *tableViewController = [YourCustomTableViewController new];
[self addChildViewController:tableViewController];
UIView *tableView = tableViewController.view;
UILabel *label1 = [UILabel new];
label1.text = #"Some text";
label1.font = [UIFont systemFontOfSize:10.0];
label1.translatesAutoresizingMaskIntoConstraints = NO;
tableView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:tableView];
[self.view addSubview:label1];
NSDictionary *views = NSDictionaryOfVariableBindings(tableView, label1);
[self.view addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:#"H:|[tableView]|" // make the tableview take the whole width
options:0
metrics:nil
views:views]
];
[self.view addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:#"H:|-3-[label1]" // attach the label 3 pixels from the left
options:0
metrics:nil
views:views]
];
[self.view addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat:#"V:|[tableView]-[label1]-3-|" // attach tableview to top, then space, then label, 3px, then bottom
options:0
metrics:nil
views:views]
];
}
#end

Autolayout issue in iOS

I have a label,image and button in a container view of type UIView . The container view is subview of supercontainerview of type UIView again. All the layout is done in code using autlayout visual format language. What i want to achieve is remove the label when a button is pressed and expecting the super container to resize its contents. but what currently happens is the whole super container disappears from the screen. Can someone tell me why this is happening? Attached is my code sample.
- (void)viewDidLoad {
[super viewDidLoad];
superContainer = [[UIView alloc] initWithFrame:CGRectZero];
superContainer.backgroundColor = [UIColor orangeColor];
[self.view addSubview:superContainer];
Container = [[UIView alloc] initWithFrame:CGRectZero];
Container.backgroundColor = [UIColor redColor];
[superContainer addSubview:Container];
NSDictionary *sViews = NSDictionaryOfVariableBindings(Container);
[superContainer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-10.0-[Container]-10.0-|" options:0 metrics:nil views:sViews]];
[superContainer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-10.0-[Container]-10.0-|" options:0 metrics:nil views:sViews]];
CGSize temp1 = [superContainer systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
superContainer.frame = CGRectMake(superContainer.frame.origin.x, superContainer.frame.origin.y, temp1.width, temp1.height);
closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
//[closeButton setImage: forState:UIControlStateNormal];
[closeButton setBackgroundImage:[UIImage imageNamed:#"closebox.png"] forState:UIControlStateNormal];
[closeButton addTarget:self action:#selector(hide:) forControlEvents:UIControlEventTouchUpInside];
NSLog(#"Close button frame is %#",NSStringFromCGRect(closeButton.frame));
//closeButton.frame = CGRectMake(0, 10, 32, 32);
[Container addSubview:closeButton];
helpLabel = [[UILabel alloc] init];
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:#"This is sample Text. This is sample Text.This is sample Text. This is sample Text.This is sample Text. This is sample Text.This is sample Text. This is sample Text.This is sample Text. This is sample Text. "];
helpLabel.attributedText = attrString;
helpLabel.numberOfLines = 0;
helpLabel.backgroundColor = [UIColor greenColor];
[Container addSubview:helpLabel];
helpImageView = [[UIImageView alloc] init];
helpImageView.image = [UIImage imageNamed:#"testimage.png"];
NSLog(#"frame of imageview is %#",NSStringFromCGRect(helpImageView.frame));
[Container addSubview:helpImageView];
dismissButton = [UIButton buttonWithType:UIButtonTypeCustom];
[dismissButton setTitle:#"Dismiss" forState:UIControlStateNormal];
[[dismissButton titleLabel] setLineBreakMode:NSLineBreakByWordWrapping];
dismissButton.backgroundColor = [UIColor blueColor];
[Container addSubview:dismissButton];
[Container setClipsToBounds:YES];
[self addAutoLayoutProperties];
NSDictionary *views = NSDictionaryOfVariableBindings(helpLabel,helpImageView,dismissButton,closeButton);
NSDictionary *metrics = #{#"buttonHeight":#32.0};
// Horizontal layout - for helplabel
[Container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-5.0-[helpLabel(400)]-5.0-|" options:NSLayoutFormatAlignAllLeft|NSLayoutFormatAlignAllRight metrics:metrics views:views]];
// Horizontal layout - for helpImageView
[Container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[helpImageView]|" options:NSLayoutFormatAlignAllLeft|NSLayoutFormatAlignAllRight metrics:metrics views:views]];
// Horizontal layout - for dismissButton
[Container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|-[dismissButton]-|" options:NSLayoutFormatAlignAllCenterX|NSLayoutFormatAlignAllCenterY metrics:metrics views:views]];
// Horizontal layout - for dismissButton
[Container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[closeButton]-1.0-|" options:0 metrics:metrics views:views]];
// Vertical layout
[Container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-1.0-[closeButton]" options:0 metrics:metrics views:views]];
[Container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-buttonHeight-[helpLabel]-5.0-[helpImageView]-5.0-[dismissButton]-5.0-|" options:0 metrics:metrics views:views]];
CGSize temp = [Container systemLayoutSizeFittingSize:UILayoutFittingExpandedSize];
Container.frame = CGRectMake(Container.frame.origin.x, Container.frame.origin.y, temp.width, temp.height);
superContainer.center = self.view.center;
}
My method to add autolayout properties
-(void)addAutoLayoutProperties {
helpLabel.translatesAutoresizingMaskIntoConstraints = NO;
helpImageView.translatesAutoresizingMaskIntoConstraints = NO;
dismissButton.translatesAutoresizingMaskIntoConstraints = NO;
closeButton.translatesAutoresizingMaskIntoConstraints = NO;
superContainer.translatesAutoresizingMaskIntoConstraints = NO;
Container.translatesAutoresizingMaskIntoConstraints = NO;
}
my methods to remove label.
- (IBAction)removeASubview:(id)sender {
[helpLabel removeFromSuperview];
}
Also one more question. What happens to the constraint objects when the related view is removed from its superview. Do they exists there or get deleted??
You can add another constraint that should be applied in the absence of the helpLabel and its constraints, but give this new one a lower priority, so that when helpLabel is present, its constraints will govern the view, but when helpLabel is removed, the new constraint will come into play. e.g.:
[container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-buttonHeight#500-[helpImageView]" options:0 metrics:metrics views:views]];
By the way, if you want to see what happened to your views after helpLabel was removed, run the app with the debugger, tap the pause button () to pause the app, and at the (lldb) debugger prompt, type the following command:
po [[UIWindow keyWindow] recursiveDescription]
Note, it can sometimes be hard to identify which window is which, so I will frequently give the various views unique numeric tag properties to make it easier.
Also, at the same command line, you can use the following command to identify ambiguous layouts in your constraints:
po [[UIWindow keyWindow] _autolayoutTrace]

Resources