navigation title overlaps bar button item after rotating back to portrait - ios

Im trying to truncate the tail of a label when the text is too long. Everything works initially (screenshots attached). Problem arises when rotate to landscape. Navigation bar extends to cover left and right navigation bar items. Same problem when rotate back to portrait. I placed border around label and nav bar to help illustrate (red for nav bar, blue for label). Is there a way to prevent nav bar from overlapping left and right bar items?
UILabel *broadcastLabel = [[UILabel alloc] initWithFrame:CGRectZero];
broadcastLabel.text = BILocalizedString(#"Broadcast with long titleeeeeeeeeeee");
[broadcastLabel sizeToFit];
broadcastLabel.textColor = BIColorForPaletteKey(BIColorPrimaryText);
broadcastLabel.font = BIFontForStyle(BIFontFixedNavigationStyle);
broadcastLabel.translatesAutoresizingMaskIntoConstraints = NO;
CGSize navBarSize = self.navigationController.navigationBar.layer.frame.size;
UIView *titleView = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, navBarSize.width, navBarSize.height)];
[titleView addSubview:broadcastLabel];
self.navigationController.navigationItem.titleView = titleView;
titleView.layer.borderWidth = 1;
titleView.layer.borderColor = [UIColor redColor].CGColor;
broadcastLabel.layer.borderWidth = 1;
broadcastLabel.layer.borderColor = [UIColor blueColor].CGColor;
[titleView addConstraint: [NSLayoutConstraint constraintWithItem:broadcastLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:titleView
attribute:NSLayoutAttributeTop
multiplier:1.f
constant:4.f]];
[titleView addConstraint: [NSLayoutConstraint constraintWithItem:broadcastLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:titleView
attribute:NSLayoutAttributeCenterX
multiplier:1.f
constant:0.f]];
[titleView addConstraint: [NSLayoutConstraint constraintWithItem:broadcastLabel
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:titleView
attribute:NSLayoutAttributeWidth
multiplier:1.f
constant:0.f]];
if (navBarSize.height >= tallSize)
{
/* Two lines*/
UILabel *onewayLabel = [[UILabel alloc] init];
onewayLabel.text = BILocalizedString(#"one-way message");
[onewayLabel sizeToFit];
onewayLabel.textColor = BIColorForPaletteKey(BIColorPrimaryText);
onewayLabel.font = BIFontForStyle(BIFontFixedSmallStyle);
onewayLabel.translatesAutoresizingMaskIntoConstraints = NO;
[titleView addSubview:onewayLabel];
[titleView addConstraint: [NSLayoutConstraint constraintWithItem:onewayLabel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:titleView
attribute:NSLayoutAttributeCenterX
multiplier:1.f
constant:0.f]];
[titleView addConstraint: [NSLayoutConstraint constraintWithItem:onewayLabel
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:titleView
attribute:NSLayoutAttributeBottom
multiplier:1.f
constant:-4.f]];
[titleView addConstraint: [NSLayoutConstraint constraintWithItem:onewayLabel
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationLessThanOrEqual
toItem:titleView
attribute:NSLayoutAttributeWidth
multiplier:1.f
constant:0.f]];
}
all three screenshots

Related

Constraints Error while trying to add button as subview

I'm trying to put a simple button within the AVPlayerViewController (for my tvOS app) in the bottom left corner of the screen above the scrub bar. I'm getting an error that indicates "Constraint items must each be a view or layout guide".
I don't have the positioning set correctly as I'm just trying to see if I can get the button to show up at all. Can someone advise why this code is crashing?
- (void)setupBreakButton
{
NSLog(#"**** In setupBreakButton....");
UIButton* skipBreakButton = [[UIButton alloc] initWithFrame:CGRectMake(50, 50, 200, 200)];
skipBreakButton.backgroundColor = [[UIColor bm_colorWithHexString:#"64A6BD"] colorWithAlphaComponent:1.0f];
skipBreakButton.layer.cornerRadius = 6;
skipBreakButton.translatesAutoresizingMaskIntoConstraints = NO;
/* Leading space to superview */
NSLayoutConstraint *leftButtonXConstraint = [NSLayoutConstraint
constraintWithItem:skipBreakButton.leadingAnchor attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual toItem:self attribute:
NSLayoutAttributeLeft multiplier:1.0 constant:30];
/* Top space to superview Y*/
NSLayoutConstraint *leftButtonYConstraint = [NSLayoutConstraint
constraintWithItem:skipBreakButton.topAnchor attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual toItem:self attribute:
NSLayoutAttributeTop multiplier:1.0f constant:258];
/* Fixed width */
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:skipBreakButton.widthAnchor
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:35];
/* Fixed Height */
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:skipBreakButton.heightAnchor
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:12];
/* 4. Add the constraints to button's superview*/
[self.view addConstraints:#[leftButtonXConstraint, leftButtonYConstraint, widthConstraint, heightConstraint]];
}
Also, how do I add this button as a subview of the AVPlayerViewController?
Inside your custom viewController call this method
UIButton* skipBreakButton;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSURL *url = [[NSURL alloc] initWithString:#""];
AVPlayer *player = [AVPlayer playerWithURL:url];
AVPlayerViewController *controller = [[AVPlayerViewController alloc] init];
[self addChildViewController:controller];
[self.view addSubview:controller.view];
controller.view.frame = CGRectMake(0,0,UIScreen.mainScreen.bounds.size.width,UIScreen.mainScreen.bounds.size.height);
controller.player = player;
controller.showsPlaybackControls = YES;
[player play];
NSLog(#"**** In setupBreakButton....");
skipBreakButton = [[UIButton alloc] initWithFrame:CGRectMake(50, 50, 200, 200)];
skipBreakButton.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:1.0f];
skipBreakButton.layer.cornerRadius = 6;
[skipBreakButton addTarget:self action:#selector(didTapButton:) forControlEvents:UIControlEventPrimaryActionTriggered];
[self.view addSubview: skipBreakButton];
skipBreakButton.translatesAutoresizingMaskIntoConstraints = NO;
/* Leading space to superview */
NSLayoutConstraint *leftButtonXConstraint = [NSLayoutConstraint
constraintWithItem:skipBreakButton attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual toItem:self.view attribute:
NSLayoutAttributeLeading multiplier:1.0 constant:30];
/* Top space to superview Y*/
NSLayoutConstraint *leftButtonYConstraint = [NSLayoutConstraint
constraintWithItem:skipBreakButton attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual toItem:self.view attribute:
NSLayoutAttributeTop multiplier:1.0f constant:258];
/* Fixed width */
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:skipBreakButton
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:35];
/* Fixed Height */
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:skipBreakButton
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:12];
/* 4. Add the constraints to button's superview*/
[self.view addConstraints:#[leftButtonXConstraint, leftButtonYConstraint, widthConstraint, heightConstraint]];
}
- (NSArray<id<UIFocusEnvironment>> *)preferredFocusEnvironments {
return #[skipBreakButton];
}
-(void)didTapButton:(UIButton *) sender {
NSLog(#"didtapbutton");
}

Even after giving vertical contraints the individual views are overlapping

I am actually trying to have UIView which houses UIImageView and UILabel (side by side). There are multiple such pairs present. I need these pairs one below the other. But after the second pair, the overlapping starts in spite of giving vertical contraints. The code below is actually resulting in Views getting overlapped (third and fourth getting on to second) I am unable to know exactly what is going wrong. Appreciate if somebody could point out this
UIView *bottomCaseStudiesLyt = [[UIView alloc]init];
bottomCaseStudiesLyt.translatesAutoresizingMaskIntoConstraints = NO;
[contentView addSubview:bottomCaseStudiesLyt];
NSLayoutConstraint* bottomCaseStudiesleftConstraint = [NSLayoutConstraint constraintWithItem:bottomCaseStudiesLyt attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeLeading multiplier:1.0f constant:10.0f];
[contentView addConstraint:bottomCaseStudiesleftConstraint];
NSLayoutConstraint* bottomCaseStudiesTopConstraint = [NSLayoutConstraint constraintWithItem:bottomCaseStudiesLyt attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:details3View attribute:NSLayoutAttributeBottom multiplier:1.0f constant:10.0f];
[contentView addConstraint:bottomCaseStudiesTopConstraint];
NSLayoutConstraint* bottomCaseStudiesRightConstraint = [NSLayoutConstraint constraintWithItem:bottomCaseStudiesLyt attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:-10.0f];
[contentView addConstraint:bottomCaseStudiesRightConstraint];
NSLayoutConstraint* bottomCaseStudiesBottomConstraint = [NSLayoutConstraint constraintWithItem:bottomCaseStudiesLyt attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f];
[contentView addConstraint:bottomCaseStudiesBottomConstraint];
//NSArray *bottomCaseStudiesVConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[headingDetailsView]-[details2View]-[details3View]-[bottomCaseStudiesLyt]|" options:0 metrics:nil views:#{#"headingDetailsView": headingDetailsView,#"details2View": details2View,#"details3View": details3View,#"bottomCaseStudiesLyt": bottomCaseStudiesLyt}];
//[contentView addConstraints:bottomCaseStudiesVConstraints];
UIView *firstView = [[UIView alloc]init];
[firstView setTranslatesAutoresizingMaskIntoConstraints:NO];
[bottomCaseStudiesLyt addSubview: firstView];
[self addImageAndDetails:bottomCaseStudiesLyt previousview:nil whichimage:#"ic_action_easy" whattext:#"Rediculously easy. Takes less than 30 seconds to build a room and go live" mynewview:firstView];
UIView *secondView = [[UIView alloc]init];
[secondView setTranslatesAutoresizingMaskIntoConstraints:NO];
[bottomCaseStudiesLyt addSubview: secondView];
[self addImageAndDetails:bottomCaseStudiesLyt previousview:firstView whichimage:#"ic_action_amaze" whattext:#"Engage members with great content, services, offers, polls, notification, quiz and more" mynewview:secondView];
UIView *thirdView = [[UIView alloc]init];
[thirdView setTranslatesAutoresizingMaskIntoConstraints:NO];
[bottomCaseStudiesLyt addSubview: thirdView];
[self addImageAndDetails:bottomCaseStudiesLyt previousview:secondView whichimage:#"ic_action_subscribers" whattext:#"Members ? No limit! There is a room for all. Go ahead and promote your room." mynewview:thirdView];
UIView *fourthView = [[UIView alloc]init];
[fourthView setTranslatesAutoresizingMaskIntoConstraints:NO];
[bottomCaseStudiesLyt addSubview: fourthView];
[self addImageAndDetails:bottomCaseStudiesLyt previousview:thirdView whichimage:#"ic_action_crossplatform" whattext:#"Your room can be accessed from any platform or device." mynewview:fourthView];
NSArray *bottomViewVConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[firsView]-[secondView]-[thirdView]-[fourthView]|" options:0 metrics:nil views:#{#"firsView": firstView,#"secondView": secondView,#"thirdView": thirdView,#"fourthView": fourthView}];
[bottomCaseStudiesLyt addConstraints:bottomViewVConstraints];
// GetStarted button
self->m_ObjGetStartedBut = [[UIButton alloc]init];
[self->m_ObjGetStartedBut setTitle: [NSString stringWithFormat:#"Get Started"] forState:UIControlStateNormal];
self->m_ObjGetStartedBut.backgroundColor = [UIColor redColor];
[self->m_ObjGetStartedBut setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
self->m_ObjGetStartedBut.translatesAutoresizingMaskIntoConstraints = NO;
self->m_ObjGetStartedBut.layer.cornerRadius = 10;
self->m_ObjGetStartedBut.clipsToBounds = YES;
[parentView addSubview:self->m_ObjGetStartedBut];
NSDictionary *myTopViews = #{
#"scrollView": self->myScrollView,
#"submitButton": self->m_ObjGetStartedBut
};
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_ObjGetStartedBut}];
[parentView addConstraints:myTopVConstraints];
[parentView addConstraints:myTopHConstraints];
//[self->m_ObjGetStartedBut addTarget:self action:#selector(buttonIsReleased:) forControlEvents: UIControlEventTouchUpInside];
//[self->m_ObjGetStartedBut setTag:1];
}
-(UIView *)addImageAndDetails:(UIView *)localparentView previousview:(UIView *)prevView whichimage:(NSString *)imageName whattext:(NSString *)relatedText mynewview:(UIView *)itemView
{
NSLayoutConstraint* topViewleftConstraint = [NSLayoutConstraint constraintWithItem:itemView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:localparentView attribute:NSLayoutAttributeLeading multiplier:1.0f constant:10.0f];
[localparentView addConstraint:topViewleftConstraint];
NSLayoutConstraint* topViewRightConstraint = [NSLayoutConstraint constraintWithItem:itemView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:localparentView attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:-10.0f];
[localparentView addConstraint:topViewRightConstraint];
NSLayoutConstraint* topViewTopConstraint = nil;
if(prevView == nil)
{
topViewTopConstraint = [NSLayoutConstraint constraintWithItem:itemView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:localparentView attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f];
[localparentView addConstraint:topViewTopConstraint];
}
else
{
//topViewTopConstraint = [NSLayoutConstraint constraintWithItem:itemView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:prevView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f];
//[localparentView addConstraint:topViewTopConstraint];
}
UIImage *easyToCreateImg = [UIImage imageNamed:imageName];
UIImageView *easyToCreateImgView = [[UIImageView alloc] initWithImage:easyToCreateImg];
easyToCreateImgView.contentMode = UIViewContentModeScaleToFill;
easyToCreateImgView.translatesAutoresizingMaskIntoConstraints = NO;
easyToCreateImgView.clipsToBounds = YES;
[itemView addSubview:easyToCreateImgView];
NSLayoutConstraint* easyToCreateImgLeftConstraint = [NSLayoutConstraint constraintWithItem:easyToCreateImgView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:itemView attribute:NSLayoutAttributeLeading multiplier:1.0f constant:2.0f];
[itemView addConstraint:easyToCreateImgLeftConstraint];
NSLayoutConstraint* easyToCreateImgTopConstraint = [NSLayoutConstraint constraintWithItem:easyToCreateImgView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:itemView attribute:NSLayoutAttributeTop multiplier:1.0f constant:2.0f];
[itemView addConstraint:easyToCreateImgTopConstraint];
NSLayoutConstraint *easyToCreateImgHtConstraint = [NSLayoutConstraint constraintWithItem:easyToCreateImgView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:80.0f];
[itemView addConstraint:easyToCreateImgHtConstraint];
NSLayoutConstraint *easyToCreateImgWidConstraint = [NSLayoutConstraint constraintWithItem:easyToCreateImgView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:80.0f];
[itemView addConstraint:easyToCreateImgWidConstraint];
UILabel* easyToCreateLblView = [[UILabel alloc]init];
[easyToCreateLblView setText:relatedText];
easyToCreateLblView.numberOfLines = 0;
UIFont *newHeadingViewLblFont = [UIFont fontWithName:#"Arial" size:13];
[easyToCreateLblView setFont:newHeadingViewLblFont];
[easyToCreateLblView setTextColor:[UIColor blackColor]];
easyToCreateLblView.translatesAutoresizingMaskIntoConstraints = NO;
[itemView addSubview:easyToCreateLblView];
NSLayoutConstraint* easyToCreateLblTopConstraint = [NSLayoutConstraint constraintWithItem:easyToCreateLblView attribute:NSLayoutAttributeCenterYWithinMargins relatedBy:NSLayoutRelationEqual toItem:easyToCreateImgView attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:2.0f];
[itemView addConstraint:easyToCreateLblTopConstraint];
NSLayoutConstraint* easyToCreateLblLeftConstraint = [NSLayoutConstraint constraintWithItem:easyToCreateLblView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:easyToCreateImgView attribute:NSLayoutAttributeRight multiplier:1.0f constant:2.0f];
[itemView addConstraint:easyToCreateLblLeftConstraint];
NSLayoutConstraint* easyToCreateLblRightConstraint = [NSLayoutConstraint constraintWithItem:easyToCreateLblView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:itemView attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:-10.0f];
[itemView addConstraint:easyToCreateLblRightConstraint];
return itemView;
}
I am not sure if my interpretation is right or wrong. What I observed is that when we give width and height constraints to the first view, this I think is not respected by the subsequent views that have been added. However, it does seem to respect the other constraints (top, bottom, leading, trailing). So when I started giving the same magnitude of width and height to the other subsequent views, then the arrangement came out as expected. Thoughts from the community are welcome.

changes subView frame when rotate

i add subView(backgroundView) in uiview in my base view controller its working well in potratate but when i change orientation from potraite to landscape its frame size is same as potrait i want to change size of subview when rotate.
UIView *activityView = [[UIView alloc] initWithFrame:self.view.bounds];
CGRect frame = activityView.frame;
activityView.frame = frame;
activityView.backgroundColor = [UIColor clearColor];
activityView.alpha = 0.0f;
[self.view addSubview:activityView];
self.activityView = activityView;
UIView *backgroundView = [[UIView alloc]initWithFrame:activityView.bounds];
backgroundView.alpha = 0.0f;
[backgroundView setBackgroundColor:[UIColor lightGrayColor]];
[self.activityView backgroundView];
UIActivityIndicatorView *spinning = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[self.activityView spinning];
spinning.center = activityView.center;
self.activityView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
[spinning setColor:[UIColor lightGrayColor]];
[spinning startAnimating];
To do this you must add constraints to your view (AutoLayout).
For example :
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:containerView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:containerView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:containerView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:containerView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:0.0]];
Edit :
Don't forget to set translatesAutoresizingMaskIntoConstraints property to NO on views.
(Replace self.view and containerView with your views).

How to make equal space b/w UIFields using auto-layouts?

I am a beginner with iOS auto-layouts and I am adding five labels on my view controller and so for every thing is OK. (Here five labels width and heights are constant.)
My main requirement is how to make equal horizontal spacing b/w that five labels. I can set middle label and left and right corner labels and they are perfect. But I don't understand how to add second left and second right labels, and how to make equal space B/W them, as like another labels?
My requirement is exact like below image, please help me.
My code:
#import "ViewController2.h"
#interface ViewController2 ()
{
UILabel * left1;
UILabel * left2;
UILabel * middle;
UILabel * right1;
UILabel * right2;
}
#end
#implementation ViewController2
- (void)viewDidLoad {
[super viewDidLoad];
left1 = [[UILabel alloc] init];
left1.backgroundColor = [UIColor grayColor];
left1.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:left1];
left2 = [[UILabel alloc] init];
left2.backgroundColor = [UIColor grayColor];
left2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:left2];
middle = [[UILabel alloc] init];
middle.backgroundColor = [UIColor grayColor];
middle.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:middle];
right1 = [[UILabel alloc] init];
right1.backgroundColor = [UIColor grayColor];
right1.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:right1];
right2 = [[UILabel alloc] init];
right2.backgroundColor = [UIColor grayColor];
right2.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:right2];
//Applying autolayouts for middle lable
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:middle
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:100]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:middle
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:10]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:middle
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:0
multiplier:1.0
constant:50]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:middle
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:0
multiplier:1.0
constant:20]];
//Appying autolayouts for left1 labe1
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:left1
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:100]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:left1
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:10]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:left1
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:0
multiplier:1.0
constant:50]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:left1
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:0
multiplier:1.0
constant:20]];
//Appying autolayouts for right1 labe1
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:right1
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:100]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:right1
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:-10]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:right1
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:0
multiplier:1.0
constant:50]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:right1
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:0
multiplier:1.0
constant:20]];
}
#end
Here is steps for you (via IB)
Create your 5 labels
Setup left and right label constraints (for left - leading, top, width, height; for right - trailing, top, width height)
Center horisontally middle label (top constraint, width, height, center horisontally)
Here is some trick - add two container views between left and middle label + middle label and right label
setup constraints for this containers ( leading and trailing constraints + top + height) This containers will be flexible depend on screen size
after adding constraints it should looks like
The last step - place other labels into green container and setup constraints as for middle label ( it should be centered in container + add top , width , height constraint )
All constraints provided at the left size, so you can easily recreate it via code, if you need
Hope this helps
So I know your question was answered, but in iOS9 there are UIStackViews which are specifically built for this situation. Here's how to use them for future reference:
Shift + click and drag to select all your labels (note you don't have to size them)
Click the StackView button on the bottom right of the screen
Then select your StackView and set Alignment to "Fill", and Distribution to "Equal Spacing"
Then with your stackview still selected click the pin icon, and put 200 at the top, 10 and 10 for the sides, and 130 for the height. Then click add 4 constraints.
Finally click the triangle icon and select update frames.
Voila! You have your layout without having to use spacers!

iOS 8 UILabel intrinsicContentSize breaking layout constraints

I have a fairly simple custom UITableViewCell subclass containing a UISwitch, UIImageView, and UILabel. All of these are subviews of the cells contentView and laid out using AutoLayout. All subviews are centered on Y and then I create a series of left and right edge constraints to arrange them horizontally. The UILabel is the rightmost item and should scale to fit between the right edge of the UIImageView to its left and the right edge of its superview. When the text it too long to fit, it should truncate. This works as expected when I test using the simulator for iOS 7.1. However, on iOS 8.1 when the text in the label is too long to fit in the allotted space, the label pushes the UIImageView to its left out of position. I have never had this issue with UILabel in the past.
Edit: I should have mentioned I get no auto layout errors when this runs.
Below are screenshots and my code:
Here is the correct behavior on iOS 7:
This what I get on iOS 8:
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
self.backgroundColor = [UIColor whiteColor];
self.contentView.backgroundColor = [UIColor whiteColor];
UISwitch *filterSwitch = [[UISwitch alloc] init];
_filterSwitch = filterSwitch;
filterSwitch.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:filterSwitch];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterSwitch
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterSwitch
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:10.0]];
UIImageView *filterImageView = [[UIImageView alloc] init];
_filterImageView = filterImageView;
filterImageView.translatesAutoresizingMaskIntoConstraints = NO;
filterImageView.backgroundColor = [UIColor redColor];
filterImageView.contentMode = UIViewContentModeScaleAspectFit;
[self.contentView addSubview:filterImageView];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterImageView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterImageView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:30.0]];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterImageView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:filterImageView
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0.0]];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterImageView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:filterSwitch
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:8.0]];
UILabel *filterLabel = [[UILabel alloc] init];
_filterLabel = filterLabel;
filterLabel.translatesAutoresizingMaskIntoConstraints = NO;
filterLabel.font = [UIFont fontWithName:#"Avenir-Medium" size:14.0];
filterLabel.textColor = [UIColor colorWithWhite:0.25 alpha:1.0];
filterLabel.textAlignment = NSTextAlignmentLeft;
filterLabel.lineBreakMode = NSLineBreakByTruncatingTail;
[self.contentView addSubview:filterLabel];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterLabel
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0.0]];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterLabel
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:filterImageView
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:8.0]];
[self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:filterLabel
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeRight
multiplier:1.0
constant:-10.0]];
return self;
}
Presumably, the horizontal compression resistance priorities of the switch and the label are the same. Therefore, the layout is ambiguous (which is not detected automatically, so no errors at run time). When both can't fit in the available width, it is arbitrary which will be compressed. So, you were just getting lucky (or unlucky, depending on how you look at it) on iOS 7.
Set the horizontal compression resistance of the label to be lower than that of the other two views so that is compresses first.
I just tried: if you set up the same situation — H:|-[switch]-[image(==30)]-[label]-| — in a view in IB and set the text of the label to be long enough, IB will tell you about the ambiguity problem.

Resources