Using NSLayoutConstraint Visual Format to set width of items - ios

I'm trying to get a hang of NSLayoutConstraints visual format and I am having a little trouble.
What I want is basically a simple UIView with two labels, one on the left, and one on the right, with heights equal to the height of the container, and the widths equal to 1/2 of the container width. The origin of the right label is aligned to the trailing of the left label.
| LEFT LABEL - RIGHT LABEL|
Anyway, here is my attempt:
self.leftLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.rightLabel.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary *views = #{ #"leftLabel" : self.leftLabel,
#"rightLabel" : self.rightLabel };
NSDictionary *metrics = #{ #"width" : #(CGRectGetWidth(self.frame) / 2) };
NSArray *constraints;
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[leftLabel]-|" options:0 metrics:metrics views:views];
[self addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[rightLabel]-|" options:0 metrics:metrics views:views];
[self addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[leftLabel(width)]" options:0 metrics:metrics views:views];
[self addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-width-[rightLabel(width)]" options:0 metrics:metrics views:views];
[self addConstraints:constraints];
[self setNeedsUpdateConstraints];
[self updateConstraintsIfNeeded];
Unfortunately, the width of each label remains 0 after this executes. Any suggestions?
UPDATE
Here's the whole class:
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
self.leftLabel = [UILabel new];
self.rightLabel = [UILabel new];
self.loadingView = [[DDLoadingView alloc] init];
self.rightLabel.backgroundColor = [UIColor redColor];
self.leftLabel.backgroundColor = [UIColor redColor];
self.backgroundColor = [UIColor blackColor];
[self addSubview:self.leftLabel];
[self addSubview:self.rightLabel];
[self configureLayout];
}
return self;
}
- (void)configureLayout
{
self.leftLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.rightLabel.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary *views = #{ #"leftLabel" : self.leftLabel,
#"rightLabel" : self.rightLabel,
#"loadingView" : self.loadingView };
NSDictionary *metrics = #{ #"width" : #(CGRectGetWidth(self.frame) / 2) };
NSArray *constraints;
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[leftLabel]-|" options:0 metrics:metrics views:views];
[self addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[rightLabel]-|" options:0 metrics:metrics views:views];
[self addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[leftLabel]-[rightLabel(==leftLabel)]-|" options:0 metrics:metrics views:views];
[self addConstraints:constraints];
[self setNeedsUpdateConstraints];
[self updateConstraintsIfNeeded];
}

You need to set the constraints to use the widths of the other views:
NSArray *constraints;
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[leftLabel]-|" options:0 metrics:metrics views:views];
[self addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[rightLabel]-|" options:0 metrics:metrics views:views];
[self addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[leftLabel]-[rightLabel(==leftLabel)]-|" options:0 metrics:metrics views:views];
[self addConstraints:constraints];
The last constraint is saying make those two views the same width while pinning them to the left/right egdes of the superview. See the Equal Widths section of the docs
As discussed in the comments, you need to also make sure that the frame of the superview can accommodate the views themselves. |-[ will use the default insets of 20, using |-2- will give insets of 2. If the intrinsic height of the labels is more than the views height minus these insets your view isn't going to show. So you either need to reduce the insets or increase the height of the container.
If you want more information on AutoLayout I recommend the following series of blog posts by #jrturton - see the top of the article for other posts in the series. He's also got a great category on UIView to make adding constraints easier, I use this daily!

Related

AutoLayout programmatically doesn't work

I want to go into the depths of auto layout and so I want to do it programmatically in order to understand it properly.I know how to use it through storyboard pretty well.Now here is what I am doing(in viewDidAppear:)
-(void)scenario2{
PGView *viewA = [[PGView alloc]initWithFrame:CGRectMake(100, 100, 100, 100) andBackgroundColor:[UIColor blackColor]];
[self.view addSubview:viewA];
PGView *viewB = [[PGView alloc]initWithFrame:CGRectMake(200, 300, 100, 100) andBackgroundColor:[UIColor yellowColor]];
[self.view addSubview:viewB];
viewA.translatesAutoresizingMaskIntoConstraints = NO;
viewB.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *constraint;
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];
//problem statement
constraint = [NSLayoutConstraint constraintWithItem:viewA attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:viewB attribute:NSLayoutAttributeWidth multiplier: 3.0f constant: 0.0f];
[self.view addConstraint:constraint];
NSLog(#"%#",viewA);
NSLog(#"%#",viewB);
}
So here I have initialized two views with different colors.
I know I need to set the property. translatesAutoresizingMaskIntoConstraints to NO before applying any new constraints. So I have done that.
Now I am specifying heights and widths of both the views.So,the x_position and y_position for both the views are 0.I run the code and I get the expected result. Both views have the specified height and width at point (0,0).
Problem
Now when I am writing the statement "problem statement" to adjust the width of viewB according to the width of viewA,its not working.
Also, when I print views viewA and viewB,it prints the frames as (0,0,0,0).
Can anyone explain me this behavior?
Edit:Here are some modifications that I have made.I have checked the ambiguity of both the views using 'hasAmbiguousLayout' and its working fine now.Now what should be the next step if I want to resize viewB's width thrice to that of viewA's width?
-(void)scenario2{
PGView *viewA = [PGView new];
viewA.backgroundColor = [UIColor yellowColor];
[self.view addSubview:viewA];
PGView *viewB = [PGView new];
viewB.backgroundColor = [UIColor blackColor];
[self.view addSubview:viewB];
viewA.translatesAutoresizingMaskIntoConstraints = NO;
viewB.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *constraint;
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];
NSLog(#"%d",viewA.hasAmbiguousLayout);
NSLog(#"%d",viewB.hasAmbiguousLayout);
NSLog(#"%#",viewA);
NSLog(#"%#",viewB);
}
The problem is that you've explicitly set width constraints for A and B to be 200 and 100, respectively. So the additional constraint that specifies that one should have a width of three times the other one is unsatisfiable when combined with the other constraints.
Furthermore, the constraints are ambiguous, as you've defined width and height constraints, but haven't defined where the two frames should be. Yes, you've defined the frame for these two views, but that is ignored when you apply the constraints. You probably shouldn't define the frame values at all, as it's misleading and confusing. But you should set, for example, the leading and top constraints, or specify those in the VFL, or add centerX and centerY constraints. You just want some constraints to dictate where the views should be placed and there's lots of ways to specify that.
And the reason that you're not seeing reasonable frame values at the end is that you've defined the constraints, but they haven't been applied yet. You could examine them in viewDidLayoutSubviews, if you wanted.
You might do something like:
- (void)scenario2 {
PGView *viewA = [PGView new];
viewA.backgroundColor = [UIColor yellowColor];
[self.view addSubview:viewA];
PGView *viewB = [PGView new];
viewB.backgroundColor = [UIColor blackColor];
[self.view addSubview:viewB];
viewA.translatesAutoresizingMaskIntoConstraints = NO;
viewB.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary *views = NSDictionaryOfVariableBindings(viewA, viewB);
// note, I added `|-100-` to say it's 100 points from the top (and 100 tall)
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-100-[viewB(==100)]" options:0 metrics:nil views:views]];
// likewise, to say 200 points from the left (and 100 wide)
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-200-[viewB(==100)]" options:0 metrics:nil views:views]];
// again, 100 from the top (as well as 200 tall)
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-100-[viewA(==200)]" options:0 metrics:nil views:views]];
// and 100 from the left
// but I've removed width definition, as we'll use your multiplier constraint below
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-100-[viewA]" options:0 metrics:nil views:views]];
// now that we've removed the width constraint from the above,
// this should now work fine
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:viewA attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:viewB attribute:NSLayoutAttributeWidth multiplier: 3.0f constant: 0.0f];
[self.view addConstraint:constraint];
// no point in doing this, because constraints haven't yet been applied
//
// NSLog(#"%#",viewA);
// NSLog(#"%#",viewB);
}
// if you want to see where they are, you could do that here:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
for (UIView *view in self.view.subviews) {
NSLog(#"%#", view);
}
NSLog(#"-----");
}

How to add two views on each other with constraints

I am trying to add 2 views with same X, Y. They have space from the edge using addConstraints:[NSLayoutConstraint constraintsWithVisualFormat...]
I tried the strings "H:|20-[A][B]-20-[C]-20-[D]-20|" and V:|20-[A][B]-20-[C]-20-[D]-20|, and centreX == CenterX and centerY==centerY, but they kept conflicting, thinking that A and B should be next to each other.
A is hidden, and on some button clicked, B is hidden and A is shown.
To add views with same centre X,Y You need to first place one of the view say bView (Bottom view), using constatins
NSArray * bVerticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"|-20-[bView]-20-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(bView)];
NSArray * bHorizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-20-[bView]-20-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(bView)];
This places the bView in the superview with 20 as edge offset.
Now place the tView (top View) with same centre as of bView. Here self is the superview of bView and tView
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[bView]-(<=1)-[tView]" options:NSLayoutFormatAlignAllCenterX metrics:nil views:NSDictionaryOfVariableBindings(bView,tView)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[bView]-(<=1)-[tView]" options:NSLayoutFormatAlignAllCenterY metrics:nil views:NSDictionaryOfVariableBindings(bView,tView)]];
Then pin the edges of tView with desired offset say 40
NSArray * tVerticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"|-40-[tView]-40-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(tView)];
NSArray * tHorizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-40-[tView]-40-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(tView)];
EDIT :
Here is how do do it.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
bView = [UIView new];
bView.backgroundColor = [UIColor redColor];
bView.translatesAutoresizingMaskIntoConstraints = NO;
tView = [UIView new];
tView.backgroundColor = [UIColor blackColor];
tView.translatesAutoresizingMaskIntoConstraints = NO;
// Firdt bView is added then tView hence tView is exaclty above the bView.
[self.view addSubview:bView];
[self.view addSubview:tView];
// Edges Constrints for bView
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|-20-[bView]-20-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(bView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-20-[bView]-20-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(bView)]];
// Edges Constints for tView
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|-20-[tView]-20-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(tView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-20-[tView]-20-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(tView)]];
// Centring for bView and tView
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[bView]-(<=1)-[tView]" options:NSLayoutFormatAlignAllCenterX metrics:nil views:NSDictionaryOfVariableBindings(bView,tView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[bView]-(<=1)-[tView]" options:NSLayoutFormatAlignAllCenterY metrics:nil views:NSDictionaryOfVariableBindings(bView,tView)]];
}
-(IBAction)toggleViews:(id)sender {
NSArray * subViews = self.view.subviews;
[self.view exchangeSubviewAtIndex:[subViews indexOfObject:tView] withSubviewAtIndex:[subViews indexOfObject:bView]];
}

need help in autolayout top layout guide, UIscrollView, UIImageView

I am working on a top sticked streach header.
My setup:
UIScrollView
-UIView(a container)
-UIImageView
-UIView(subContent view)
What i want:
Stick UIImageView to top layout guide.
UIImageView height is 100 - 250. That is UIImageView height is initialise with 250, but can not be less than 100.
0 top space in between UIImageView and subContentView.
So when user scroll towards bottom, UIImageView will gradually minimise and will no more minimise as soon as it's height reaches 100(minimum height).
BUT subContentView must not overlap my UIImageView and be able to scroll till end (accurate content size/ offset)
What i am able to do is:
i am able to stick UIImageView to top based on layout guide.
I am also able to acheive height range of UIImageView on scroll top or bottom (increase and decrease height).
BUT i am not able to stop UIImageView from being overlapping by my subContentView.
That is when i scroll to bottom my UIImageView remains stick to top and gradually decreases it's size, at the moment it reaches to height 100,(i am still scrolling bottom) my subContentView starts overlapping my UIImageVIew.
How ever it makes sense as i have no set constraints from top layout guide to subcontent view.
some thing like:
format = #"V:|[topGuide]-**some dynamic value based on UIImageViewHeight**-[subContentView]";
How do i achieve this.
Please help me i am working on it from a day, and finally i decided to ask.
my code:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.navigationItem.title = #"Programmatically";
NSMutableDictionary* views = [NSMutableDictionary new];
views[#"super"] = self.view;
views[#"topGuide"] = self.topLayoutGuide; // The bottom of the navigation bar, if a navigation bar is visible. The bottom of the status bar, if only a status bar is visible .. etc...
//Create the ScrollView
UIScrollView* scrollView = [UIScrollView new];
scrollView.delegate = self;
scrollView.translatesAutoresizingMaskIntoConstraints = NO; //we are using auto layout
self.automaticallyAdjustsScrollViewInsets = NO;
[self.view addSubview:scrollView];
views[#"scrollView"] = scrollView;
//Create the scrollview contentview
UIView* contentView = [UIView new];
[contentView setBackgroundColor:[UIColor yellowColor]];
contentView.translatesAutoresizingMaskIntoConstraints = NO; //we are using auto layout
[scrollView addSubview:contentView];
views[#"contentView"] = contentView;
//Add the image view and other addtional views to the content view
topImageView = [[WAPlayerDetailHeader alloc] initWithFrame:CGRectZero andImage:nil];
topImageView.translatesAutoresizingMaskIntoConstraints = NO; //we are using auto layout
topImageView.contentMode = UIViewContentModeScaleAspectFill;
topImageView.clipsToBounds = YES;
[contentView addSubview:topImageView];
views[#"topImageView"] = topImageView;
//Add other content to the scrollable view
UIView* subContentView = [UIView new];
[subContentView setBackgroundColor:[UIColor redColor]];
subContentView.translatesAutoresizingMaskIntoConstraints = NO; //we are using auto layout
[contentView addSubview:subContentView];
views[#"subContentView"] = subContentView;
//Now Let's do the layout
NSArray* constraints;
NSString* format;
NSDictionary* metrics = #{#"imageHeight" : #250.0};
//======== ScrollView should take all available space ========
format = #"|-0-[scrollView]-0-|";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[self.view addConstraints:constraints];
format = #"V:[topGuide]-0-[scrollView]-0-|";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[self.view addConstraints:constraints];
//======== ScrollView Content should tie to all four edges of the scrollview ========
format = #"|-0-[contentView]-0-|";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[scrollView addConstraints:constraints];
format = #"V:|-0-[contentView]-0-|";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[scrollView addConstraints:constraints];
// ========== Layout the image horizontally
format = #"|-0-[topImageView(==super)]-0-|"; // with trick to force content width
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[self.view addConstraints:constraints];
// ========== Put the sub view height, and leave room for image
format = #"|-0-[subContentView]-0-|";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[scrollView addConstraints:constraints];
// we leave some space between the top for the image view
format = #"V:|-imageHeight-[subContentView(1000)]-0-|"; /*the view height is set to 700 for the example in order to have enough content */
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:metrics views:views];
[scrollView addConstraints:constraints];
// Start of the magic
format = #"V:[topImageView]-0-[subContentView]"; // image view bottom is subcontent top
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[contentView addConstraints:constraints];
// image view top is the top layout
format = #"V:|[topGuide]-0-[topImageView(>=100)]";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[self.view addConstraints:constraints];
//Optional stuff, Add The A view
aView = [[WAPlayerDetailHeader alloc] initWithFrame:CGRectZero andImage:nil];
[aView setAlpha:1.0];
aView.translatesAutoresizingMaskIntoConstraints = NO; //we are using auto layout
aView.backgroundColor = [UIColor colorWithRed:0.79 green:0.9 blue:0.69 alpha:1];
[subContentView addSubview:aView];
views[#"aView"] = aView;
format = #"|[aView]|";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[subContentView addConstraints:constraints];
format = #"V:|-[aView(127)]-5-|";
constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];
[subContentView addConstraints:constraints];
}
this is what happening video demo
i am following this code from this location
i have upload on git download and you can see

How to draw a horizontal line using UIView and autolayout?

Here is the code I have...this is kind of a simple question...perhaps I shouldn't do it with UIView...but I just wanna draw a decorative horizontal line to separate content. What I am getting is no error the line just does not draw. If I init it with a frame and turn off autolayout, then I do see the line but that's not how I want to implement it since everything is autolayout.
Below the viewDidLoad calls the other methods to create the UI elements and add the constraints.
- (void)viewDidLoad {
[super viewDidLoad];
// Add main layout
[self.scrollView addSubview:self.profileInfoContainer];
// Add UI elements
[self.profileInfoContainer addSubview:self.email];
[self.profileInfoContainer addSubview:self.userName];
[self.profileInfoContainer addSubview:self.hLineSeperator];
[self.profileInfoContainer addSubview:self.navigationContainer];
// Add Constraints
[self addInfoContainerConst];
}
Below i add the constraints for all ui elements in the profileInfoContainer, including the hLineSeperator
- (void)addInfoContainerConst {
// Add constrains
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_userName, _email, _hLineSeperator, _navigationContainer);
NSDictionary *metrics = #{
#"vTop":#60,
#"vBttm":#5,
#"hLeft":#25,
#"hRight":#25,
#"vMiddle":#5
};
NSArray *constraint_POS_V = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-vTop-[_userName]-vMiddle-[_email]-vMiddle-[_hLineSeperator]-vMiddle-[_navigationContainer]|"
options:0
metrics:metrics
views:viewsDictionary];
NSArray *constraint_POS_H = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-hLeft-[_userName]-hRight-|"
options:0
metrics:metrics
views:viewsDictionary];
NSArray *constraint_POS_H_1 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-hLeft-[_email]-hRight-|"
options:0
metrics:metrics
views:viewsDictionary];
NSArray *constraint_POS_H_2 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_hLineSeperator(1)]|"
options:0
metrics:metrics
views:viewsDictionary];
NSArray *constraint_POS_H_3 = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[_navigationContainer]|"
options:0
metrics:metrics
views:viewsDictionary];
[self.profileInfoContainer addConstraints:constraint_POS_V];
[self.profileInfoContainer addConstraints:constraint_POS_H];
[self.profileInfoContainer addConstraints:constraint_POS_H_1];
[self.profileInfoContainer addConstraints:constraint_POS_H_2];
[self.profileInfoContainer addConstraints:constraint_POS_H_3];
}
Below is the method to create the UIView that is used to draw the line
- (UIView*)hLineSeperator {
if (!_hLineSeperator) {
_hLineSeperator = [UIView new];
_hLineSeperator.translatesAutoresizingMaskIntoConstraints = NO;
_hLineSeperator.backgroundColor = [UIColor grayColor];
}
return _hLineSeperator;
}
It is not required to add constraints to subviews (specifically like the ones you want to create) created in code. You can do it something like,
UIView *horizontalSeperatorViewOnTop = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.(yourView).frame.size.width, 0.5f)];
horizontalSeperatorViewTop.backgroundColor = [UIColor lightGrayColor];
[self.(yourView) addSubview: horizontalSeperatorViewOnTop];
I do this in my code all the time for horizontal or vertical separators and it works great!

iOS constraints not updating as expected

I have a superview with circle view and a holderview that contains 3 labels as subview and is centred to the superview as seen in image
I have added constraints to the 3 labels with respect to holderview and also added constraints to holderview with respect to superview
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(titleLabel);
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"|-[titleLabel]-|"
options:0
metrics:nil
views:viewsDictionary];
[holderView addConstraints:constraints];
viewsDictionary = NSDictionaryOfVariableBindings(setLabel);
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"|-[setLabel]-|"
options: 0
metrics:nil
views:viewsDictionary];
[holderView addConstraints:constraints];
viewsDictionary = NSDictionaryOfVariableBindings(repLabel);
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"|-[repLabel]-|"
options:0
metrics:nil
views:viewsDictionary];
[holderView addConstraints:constraints];
viewsDictionary = NSDictionaryOfVariableBindings(titleLabel, setLabel, repLabel);
constraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[titleLabel]-0-[setLabel]-0-[repLabel]-|"
options:0
metrics:nil
views:viewsDictionary];
[holderView addConstraints:constraints];
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_labelView);
NSArray *constraints =[NSLayoutConstraint constraintsWithVisualFormat:#"|-[_labelView]-|"
options:0
metrics:nil
views:viewsDictionary];
[self addConstraints:constraints];
There is a feature in app where the circle shrinks. I want the holderview and its subivews to shrink dynamically. Adding the constraints works for holderview but the subviews get misaligned.
To shrink i update the frame size of the holderview as the superview frame changes.
Can anyone point out the mistakes and guide me to proper solution ?
Using auto layout and changing frame property messes up things.
Create oultest to the constraints that you want to change or animate
__weak IBOutlet UIView *settingsView;
__weak IBOutlet NSLayoutConstraint *settingsBottomConstraint;
__weak IBOutlet NSLayoutConstraint *settingsViewHeightConstraint;
Update the constrains(Never the frame!)
settingsBottomConstraint.constant = - settingsViewHeightConstraint.constant;
[settingsView setNeedsUpdateConstraints];
[settingsView layoutIfNeeded];
isSettingsHidden = YES;
Recently I have worked with animation of views with autolayout and you can find your answer here
Auto Layout constraint change does not animate
You can also use the function updateConstraints.
[settingsView updateConstraints];

Resources