how to do uilabel programmatically in auto layout - ios

I am doing a project in auto layout in Xcode 6, I am adding a label programmatically its working perfectly in 4s,5,5s but in 6 and 6 plus is not working. can anyone help me, I am new to auto layout.Below is my coding.
UIScrollView *scroll = [[UIScrollView alloc]init];
[scroll setTranslatesAutoresizingMaskIntoConstraints:NO];
scroll.contentSize=CGSizeMake(480, 600);
[centerView addSubview:scroll];
NSDictionary *scrolldic = #{#"scrollview":scroll};
NSArray *scroll_H = [NSLayoutConstraint constraintsWithVisualFormat:#"H:[scrollview(480)]" options:0 metrics:Nil views:scrolldic];
NSArray *scroll_V = [NSLayoutConstraint constraintsWithVisualFormat:#"V:[scrollview(480)]" options:0 metrics:Nil views:scrolldic];
[scroll addConstraints:scroll_H];
[scroll addConstraints:scroll_V];
NSArray *scroll_posH = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[scrollview]" options:0 metrics:Nil views:scrolldic];
NSArray *scroll_posV = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[scrollview]" options:0 metrics:Nil views:scrolldic];
[self.view addConstraints:scroll_posH];
[self.view addConstraints:scroll_posV];
UILabel *header = [[UILabel alloc]init];
[header setTranslatesAutoresizingMaskIntoConstraints:NO];
header.backgroundColor = [UIColor blueColor];
[scroll addSubview:header];
NSDictionary *headerdic = #{#"header":header};
NSArray *header_H = [NSLayoutConstraint constraintsWithVisualFormat:#"H:[header(150)]" options:0 metrics:Nil views:headerdic];
NSArray *header_V = [NSLayoutConstraint constraintsWithVisualFormat:#"V:[header(30)]" options:0 metrics:Nil views:headerdic];
[header addConstraints:header_H];
[header addConstraints:header_V];
NSArray *header_posH = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-80-[header]" options:0 metrics:Nil views:headerdic];
NSArray *header_posV = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-20-[header]" options:0 metrics:Nil views:headerdic];
[self.view addConstraints:header_posH];
[self.view addConstraints:header_posV];
see the above image in 4s label is in center is correct , but in 6 it move to some left, what is the problem can any one help me.

To get it to work, it is also important how you want the layout to look on different devices. Should the label always have the width 150 and be centered or should it always have a 80 left and right padding?
This is what you have to decide but the constraints would look like this:
First case (same width and centered) :
NSLayoutConstraint *centerXConstraint = [NSLayoutConstraint constraintWithItem:header attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem: scroll attribute:NSLayoutAttributeCenterX multiplier:1.f constant:0];
[scroll addConstraint:centerXConstraint];
Second case (keep the padding between devices):
[scroll addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-leftPadding-[header]-leftPadding-|" options:0 metrics:#{ #"leftPadding": #(80) } views:#{ #"header": header }]];
Let me know hot it goes or if you need more help.

Try adding your constraint like this
NSLayoutConstraint *leadingConstraint= [NSLayoutConstraint constraintWithItem:self.contentView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yourLabel attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
NSLayoutConstraint *topConstraint= [NSLayoutConstraint constraintWithItem:self.contentView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:_yourLabel attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
[self.contentView addConstraints:#[leadingConstraint,topConstraint]];

The issue seems to be that you have hard coded the values in. This is fine for iPhone 4 and 5 as they both have screens with width of 320. This means your hard coded value of 80 keeps it in the middle.
iPhone 6 though has a wider screen
iPhone 4 and 5
|---80---|--150--|---90---|
You can see this with a screenshot of your screenshot above:
Here I have added two green lines both the same length, although you think your label is in the middle on iPhone 4 and 5 it actually isn't.
What you need to do is one of two things:
Use NSLayoutConstraints to fix the view in the middle instead of setting values. There are various layout constraints that put it in the middle.
You can use centreX for this
NSLayoutConstraint * centreConstraint = [NSLayoutConstraint constraintWithItem:self.contentView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yourLabel attribute:**NSLayoutAttributeCenterX** multiplier:1.0 constant:0];
Then add this constraint (NSLayoutConstraint can be quite fiddly so make sure you test it as this might not work)
This sets the label in the middle of the screen (hence the centreX - meaning centre of the x-axis)
The other way, not recommended if you are trying to have both landscape and portrait orientations, would be to calculate the width of the screen and so enter an accurate half way padding value.
You can calculate the width of the screen with
[UIScreen mainScreen].bounds.size.width
Then you can calculate the value you need it to be Eg in your case it would be
// Your label is 150 pixels wide so the space on each side is the width less 150 but half as you have the same amount on each side.
([UIScreen mainScreen].bounds.size.width - 150)/2
This is a way to simply calculate the value needed and is not as good as using NSLayoutConstraint. It is much simpler but much less versatile. I only include it for completeness.
My advice, look on some tutorials for NSLayoutConstraints this one is good and get better understanding of what you are constraining.

Related

AwakeFromNib auto layout stretch UIlabel to spacing on both side programmatically

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

How to automatically change height of UILabel object and position of other elements below, based on the content of UILabel, with autolayout enabled

I've found some answers related to this topic, but nothing works for me. I've tried setPreferredMaxLayoutWidth:, setting number of lines to 0, setting height constraint
to XYZ, or equal or greater than XYZ... and all that in many different combinations. What could be possibly wrong? Any ideas?
Selected label is the one that needs to change the height based on content. Label below it, and possible other elements below should move down if the label has content that doesn't fit in 1 line. There are no constraint problems reported by IB.
Here's how I've just successfully done it:
I set numberOfLines on the label to 0, so it will grow and shrink as necessary.
I gave the label >= 0 left and right leading/trailing space constraints to the container margins, so it can grow to a maximum width.
I did not put any height constraint on the label. The height will therefore be determined by the content.
I made sure that no vertical constraints on anything below the label were limiting its downward growth.
In particular, bear in mind that if you set a constraint from anything to the bottom of the screen, you'll need to make sure that its priority (or the priority of another vertical constraint in the chain from the label to the bottom) is set to a lower priority than the vertical Content Compression Resistance Priority of the label. This will make sure that the growth of the label's content can overcome the other vertical constraints.
If you are using Auto Layout in code, setting the frame does not work. You have to create the constraint set required for the layout you want. For this case you would need to add height constraints for your UILabel.
Full tutorial on how to do is here : http://www.thinkandbuild.it/learn-to-love-auto-layout-programmatically/
if you want to try to take care of it in code then you can approach it like this. i've laid out something akin to what you have then after 5 seconds it will swap in a new vertical constraint to make one of the labels taller. hope it steers you in the right direction ... or at least a direction!
NSArray * vertConstraint;
UIImageView * imageView = [[UIImageView alloc] init];
UILabel * labelOne = [[UILabel alloc] init];
UILabel * labelTwo = [[UILabel alloc] init];
UILabel * labelThree = [[UILabel alloc] init];
imageView.backgroundColor = [UIColor grayColor];
labelOne.backgroundColor = [UIColor redColor];
labelTwo.backgroundColor = [UIColor blueColor];
labelThree.backgroundColor = [UIColor orangeColor];
[imageView setTranslatesAutoresizingMaskIntoConstraints: NO];
[labelOne setTranslatesAutoresizingMaskIntoConstraints: NO];
[labelTwo setTranslatesAutoresizingMaskIntoConstraints: NO];
[labelThree setTranslatesAutoresizingMaskIntoConstraints: NO];
[self.view addSubview:imageView];
[self.view addSubview:labelOne];
[self.view addSubview:labelTwo];
[self.view addSubview:labelThree];
id topGuide = self.topLayoutGuide;
id bottomGuide = self.bottomLayoutGuide;
NSDictionary * viewsDictionary = NSDictionaryOfVariableBindings(imageView, labelOne,labelTwo,labelThree,topGuide, bottomGuide);
// initial vertical constraints. will be swapped out after 5 seconds (See below
vertConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[topGuide]-100-[imageView(==200)]-20-[labelOne(==20)]-20-[labelTwo(==20)]-20-[labelThree(==20)]-(>=5)-[bottomGuide]|" options:0 metrics: 0 views:viewsDictionary];
[self.view addConstraints:vertConstraint];
// horizontal constraints for all the elements
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(>=0)-[imageView(==200)]-(>=0)-|" options:0 metrics: 0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(>=0)-[labelOne(==200)]-(>=0)-|" options:0 metrics: 0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(>=0)-[labelTwo(==200)]-(>=0)-|" options:0 metrics: 0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(>=0)-[labelThree(==200)]-(>=0)-|" options:0 metrics: 0 views:viewsDictionary]];
//additional constraints to center them
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:imageView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:labelOne
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:labelTwo
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:labelThree
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
//delay 5 seconds then swap out vertical constraints
// in this case change the (==20) to (==40) for height of element
// you can edit that string more dynamically to fit your needs
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
NSArray * newVertConstraint = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[topGuide]-100-[imageView(==200)]-20-[labelOne(==20)]-20-[labelTwo(==40)]-20-[labelThree(==20)]-(>=5)-[bottomGuide]|" options:0 metrics: 0 views:viewsDictionary];
[self.view removeConstraints:vertConstraint];
[self.view addConstraints:newVertConstraint];
[self.view setNeedsUpdateConstraints];
[UIView animateWithDuration:1.5 animations:^{
[self.view layoutIfNeeded];
}];
});

Work with Autolayout programmatically

i try to achieve the following Design with UIView´s, it should be all done with Autolayout and no hard coded Frames:
I do it with an "for loop" like this:
CGFloat y_coordinate = 0;
for(int i = 0;i < 3;i++)
{
UIView * testView = [UIView new];
testView.frame = CGRectMake(testView.frame.origin.x, y_coordinate, testView.frame.size.width, testView.frame.size.height);
testView.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary *viewsDictionary = #{#"testView":testView};
testView.backgroundColor = [UIColor redColor];
[self.view addSubview:testView];
//View should have the same Width and Height and a little Padding between them!
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:testView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:0.5
constant:-4]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:testView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:testView
attribute:NSLayoutAttributeHeight
multiplier:1
constant:-4]];
if(i % 2) {
//odd
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[testView]-0-|"
options:0
metrics:nil
views:viewsDictionary]];
//Here i need the Height of the View and not hard coded like here...but how?
y_coordinate += 200;
} else {
//even
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[testView]"
options:0
metrics:nil
views:viewsDictionary]];
}
}
My Problem is that i don´t know how to place the Views correctly under each other with Autolayout?
My Suggestion to you will be go through the auto layout tutorials online, and have a clear understanding of how the views layout themselves under "Autolayout".
One such example would be Ray Wenderlich's tutorial. Although this tutorial has not been dedicated for doing autolayout programmatically, but it does give a clear understanding of how the views are placed with the help of autolayout feature.
http://www.raywenderlich.com/50317/beginning-auto-layout-tutorial-in-ios-7-part-1
#deathhorse answer may work but the metrics argument is designed for this...
NSDictionary *metrics = #{#"margin": #(y_coordinate)};
[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(margin)-[testView]"
options:0
metrics:metrics
views:NSDictionaryOfVariableBindings( testView )]];
This makes it more readable too.
EDIT
Having looked at your question again I think you are going about this the wrong way anyway.
Yes, you can use Auto Layout inside the views to lay out the labels and image and stuff....
However, this view should be using a UICollectionView and not just laid out in a for loop like this. Even if you're only adding 4 and you don't want it to scroll it would be much more flexible as a UICollectionView.
that's quite simple, create your constraint like this
[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"V:|-(%.0f)-[testView]", y_coordinate]
options:0
metrics:nil
views:NSDictionaryOfVariableBindings( testView )]];

Creating constraint to center label in view

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

How to resize custom UITableView separators on landscape and prevent from disappearing

I've decided to programmatically create my own UITableView separator lines because I need fine control over displaying a separator above and/or below each individual UITableViewCell. My tableView has static cells, so I do not create the separators in cellForRowAtIndexPath. Instead, I have propertys for each cell and in viewDidLoad, I add a top and/or bottom separator as needed. It's working, until I rotate to landscape and then the separator line does not stretch to fill the screen - it of course remains the same width it was when created. I'm not seeing how I can automatically adjust them to fit the width of the screen.
I tried adding Auto Layout constraints (leading, trailing, top/bottom), but for some reason it's not working - the width does not change, but there are no error messages logged to indicate anything is wrong with the constraints. The separator lines also sometimes disappear upon scroll or rotate, and if I comment out the auto layout constraints then they do not disappear.
So how can I make my custom cell separators always stretch to fill the device width upon rotation, and how do I prevent them from disappearing?
If it would be easier/better to create my custom cell separators in a different way, I am willing to do that. I just don't know how this can be done aside from my approach when the cells are static. I considered creating the views in the Storyboard, and setting up the constraints visually, but would that not be the equivalent of what I'm doing programmatically? If they were dynamic cells I would do it in cellForRowAtIndexPath.
//In viewDidLoad:
[self addTopSeparatorForCell:self.myCell];
//Helper method
- (void)addTopSeparatorForCell:(UITableViewCell *)cell {
UIView *topSeparator = [[UIView alloc] initWithFrame:CGRectMake(15, 1, cell.contentView.frame.size.width, 0.5)];
//add CALayer to preserve line separator visibility when row is highlighted
CALayer *backgroundColorLayer = [CALayer layer];
backgroundColorLayer.frame = topSeparator.bounds;
backgroundColorLayer.backgroundColor = [UIColor colorWithWhite:204/255.0f alpha:1].CGColor;
[topSeparator.layer addSublayer:backgroundColorLayer];
[cell.contentView addSubview:topSeparator];
//add auto layout constraints
topSeparator.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *cn = nil;
cn = [NSLayoutConstraint constraintWithItem:topSeparator
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:cell.contentView
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:15];
[cell.contentView addConstraint:cn];
cn = [NSLayoutConstraint constraintWithItem:topSeparator
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:cell.contentView
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:0];
[cell.contentView addConstraint:cn];
cn = [NSLayoutConstraint constraintWithItem:topSeparator
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:cell.contentView
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:1];
[cell.contentView addConstraint:cn];
}
EDIT: Thanks to # user1966109, we've been able to solve the issue with the lines not extending to fill the width, and now they are preserved when highlighting a cell. But one issue still remains that I haven't been able to solve, since I'm not sure why it's occurring. The separator lines disappear after scrolling down the scrolling back up. It's related to the auto layout constraints though because a previous solution which had other issues did not exhibit this problem. Here's the current solution that causes the lines to disappear. I'd appreciate it if someone knows how to prevent this problem (and preserve the other issues already resolved).
[self.cell addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(15#750)-[myView]-(-47#750)-|" options:0 metrics:0 views:viewsDictionary]];
[self.cell addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[myView(2)]-(-2#750)-|" options:0 metrics:0 views:viewsDictionary]];
You should not mix initWithFrame and Auto Layout. You can have a good result with a few lines using Visual Format Language for Auto layout:
//#interface TableViewController ()
#property (weak, nonatomic) IBOutlet UITableViewCell *cell;
//#implementation TableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *myView = [[UIView alloc] init];
myView.backgroundColor = [UIColor redColor];
[self.cell.contentView addSubview:myView];
myView.translatesAutoresizingMaskIntoConstraints = NO;
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(myView);
[self.cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[myView]|" options:0 metrics:0 views:viewsDictionary]];
[self.cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[myView(2)]" options:0 metrics:0 views:viewsDictionary]];
}
This handles rotation perfectly.
Edit!
Set the following constraints if using a accessory view:
//Set a negative value to the trailing space in order to display myView under the accessory view
//Those constraints work for both self.cell and self.cell.contentView (kind of odd)
[self.cell addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(15#750)-[myView]-(-47#750)-|" options:0 metrics:0 views:viewsDictionary]];
[self.cell addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[myView(2)]-(-2#750)-|" options:0 metrics:0 views:viewsDictionary]];
With the initial help of user1966109, I have figured out constraints that address all of the problems and are working well:
[cell addConstraint:[NSLayoutConstraint constraintWithItem:imageView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:cell
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:indent]];
[cell addConstraint:[NSLayoutConstraint constraintWithItem:imageView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:cell
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:0.0]];
[cell addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[imageView(0.5)]" options:0 metrics:0 views:viewsDictionary]];

Resources