AutoLayout setting UILabel height to zero - ios

I have a UILabel for item description amongst other views, all laid out using constraints in Interface Builder - you can see all relevant constraints in the image below. The number of lines is also set to 0.
I haven't set the height constraint because I want the UILabel to resize based on the text it contains. Instead, what happens is right after
[self.view layoutIfNeeded];
is called, the height of the UILabel gets set to 0. Even if I don't set other text to the UILabel, it has a default value of Item description set in Interface Builder.
The item title label above is set the same way, but that one doesn't get squashed to 0, so I'm a bit confused.
Anyone had any experience with such behaviour?

I managed to solve it by setting the UILabel's vertical compression resistance priority to 1000 (default 750) in Interface Builder.
Since my views are embedded in another view, and the parent view's bottom is dependent on the bottom of the lowest child view, I only speculate that the UILabel without a height constraint was getting squeezed in the process of laying out the views. Probably playing with priorities of other constraints somewhere down the chain would have yielded the same result, but I wasn't able to do it successfully. The solution above, however, worked, which is good enough in my case.
Hope this helps someone.

Set 3 constraint
1.Leading space to superview
2.Trailing space to superview
3.Top space to superview
then
#property (nonatomic, strong) IBOutlet UILabel *lbl;
- (void) viewDidLoad{
[self.lbl sizeToFit];
}

ctrl drag from the label to itself > select height > set the constant of the height to 0 and change equal (==) to greater than or equeal (>=)

I think you need to set 5 constraints on your label :
Leading space to superview
Trailing space to superview
Vertical space to "Item"
Vertical space to "Name"
Height
Then add an IBOutlet in your controller on the constraint height (let's say labelHeight).
So in your viewDidLoad you will be able to set this constraint value:
#property (weak, nonatomic) IBOutlet UILabel *label;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *labelHeight;
- (void) viewDidLoad{
[self.label sizeToFit];
labelHeight.constant = self.label.frame.size.height;
}

AutoLayout in this UIViewController can't satisfy all the constraints you have set, therefore it dismiss those on your UILabel, resulting in a compressed state. You should have a look at the other constraints in your UIViewController, and set the priority of the height contraint to a higher number.

Related

Updating width of uilabel when subview not

I have UILabel in a UITableViewCell whose neighboring subview is UIControlSwitch. When the UIControlSwitch is hidden, the UILabel's width is expected to grow. Below is my custom class implementation:
- (void)setBounds:(CGRect)bounds
{
[super setBounds:bounds];
self.contentView.frame = self.bounds;
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self.contentView updateConstraintsIfNeeded];
[self.contentView layoutIfNeeded];
self.numberLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.numberLabel.frame);
self.quoteLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.quoteLabel.frame);
}
#end
I have uploaded a sample code to explain the constraints on the storyboard.
The UILabel's width is not changing. If I set a trailing space between the UILabel and the UIControlSwitch, the control is partially hidden beyond the screen bounds. Hence the constraint for the UILabel has trailing space to the superview instead of the UIControlSwitch.
When you hide a view, it still takes part in the layout process. So simply hiding your UISwitch will not cause anything to change.
So you either have to add/remove constraints, remove the UISwitch from its containing view or change how you are doing the constraints.
Option 1: Instead of hide/show do remove/add.
If you put the UISwitch in its own view, you can pin the UILabel to the switches containing view. Instead of hiding the UISwitch, remove it from its containing view. The result will be that the containing view collapses and your UILabel will stretch as long as the label is pinned to the switches view and the switches view to the edge.
Instead of show, add the UILabel back into the container view. The view will stretch and your UILabel will shrink.
Option 2: Use simple trailing constraint for UILabel.
Make your UILabel have a trailing constraint to the superview and CTRL drag that constraint into your code so you can set its value. Or you could add it manually if that is what you are doing.
Do not pin the UILabel to the UISwitch at all. Pin the UILabel to the right h§and side so it has the required position.
So your UILabel is now pinned to the right edge with an offset of your choosing. If you set this small, the UILabel will be over/under the switch. If set to the width of the switch plus left and right margin it will appear to stretch up to the switch.
In your code, you can find the width of the UISwitch by looking at its frame.
1) When the UISwitch is to be visible, set the trailing pin constraint of the UILabel to be the margin you want + width of UISwitch + margin to left of UISwitch you want.
2) When the UISwitch is to be hidden, set the trailing pin constraint of the UILabel to be the margin you want to the superview.
This should then cause the UILabel to extend to the switch when not hidden, or to the edge when the switch is hidden.

How to set autolayouts and content size in xib for multiline label in scroll view

I am using autolayout. In xib i have a scrollview as a parent view. Added one view as a subview. For that subview i have added four child elements. Three are views(say view1,view2,view3) and one is label which is having multiline text.
I am using the below code to change the height of the view
#property (strong, nonatomic) IBOutlet NSLayoutConstraint *view1Height;
self.view1Height.constant = 200;
In this case there is no issues with content size the view2 and view3 frames are adjusted automatically.
But while coming to multiline label I am using the below code for setting label text
#property (strong, nonatomic) IBOutlet NSLayoutConstraint *textLabelHeight;
self.textLabelHeight.constant = expectedLabelSize.height;
But here I am facing issue with scroll content size. Unable to view the entire text. Similarly I want to place one more view below the label how to set constraints for it.

Center contents of UIScrollview when using autolayout

I'm using autolayout in my project and I have a scrollview that has a button centered in it. I have gotten the scrollview to scroll, but not to take up the entire screen.
I've tried to follow the tutorial here: https://developer.apple.com/library/ios/technotes/tn2154/_index.html, as well as I have checked out a few similar questions on here. The issue is that I want the contents of the scrollview to center, rather than be pinned to the top/bottom/left/right.
Here is my view hierarchy:
Could you please help me out?
You have added constrains between your scroller view and its super view. These constrains determines the frame of the scroll view. You can think of the scroll view as a window, through which you can see the the contents behind. The frame is the just the size of the window. Of course, you can slide the window, which gives you the sights of parts of the contents.
Now you have the size of the window, but you also need to tell Xcode the size of the contents. If you just say put everything in the middle without telling the width, how can Xcode know where is the middle?
So, you have to tell the width (as well as height). Let's think about a simple example, how to center a single label in a scrollview.
You should first pin the edges of the scroll view to its super view just as what you did. After that you should add constraints between the edges of the label and the edges of the scroll view, besides, you should also add the with and the height constraints of the label.
The leading space, the trailing space and the width together give the with of the contents, while the top space, bottom space and the height together give the height of the contents.
|---leading space---|label width|---trailing space---|
|---------- content with of the scroll view -------------|
But you may want to set the with of the content view equal to the with of your screen, then you need to do some programming. Set there outlet properties in you code
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *trailingSpace;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *leadingSpace;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *width;
In your viewWillLayoutSubviews do this
CGFloat contentWidth = self.view.frame.size.width;
CGFloat horiPadding = (contentWidth - self.width.constant) / 2;
_trailingSpace.constant = horiPadding;
_leadingSpace.constant = horiPadding;
Now you the label is at the horizontal center of you scroll view! Your scroll view has already knew the with of its contents, so you don't need to do this for any other view you added in your scroll view: you can just add the center constraint.
You can also do the same thing for the height.

iOS how to make dynamic width / autolayout of UIView according to UILabel within it

I am struggling with maybe a bit of a rookie issue. I have a UIView within which I display some price. I want the UIView to be of a dynamic width according to the price, if its 1 Euro, then it will be e.g. 20pt, if its 2300 Euro, then it will be like 50pt in width.
I was trying to use the storyboard's constraints but without luck. Is it possible to do it within storyboard or do I have to calculate the width of UILabel and then set the width of UIView programmatically?
Thank you in advance.
Yes, you can do this in the storyboard. Add a label to your view and pin it to the left and right edge (top and bottom if you want also). Give the view constraints to its superview in the x and y directions, but do not give it a width constraint (it will need a height constraint if you didn't pin the top and bottom of the label to it). The view should then expand with the label depending on its content.
In general, auto layout is performed in a top-down fashion. In other words, a parent view layout is performed first, and then any child view layouts are performed. So asking the system to size the parent based on the child is a bit like swimming upstream, harder to do, but still possible with some work.
One solution is to use the intrinsic size of a view.
For example, a UILabel has an intrinsic size based on the text in the label. If a UILabel has a leading constraint and a top constraint, but no other constraints, then its width and height are determined by its intrinsic size.
You can do the same thing with a custom view class that encloses a UILabel. By setting the intrinsic size of the custom view class based on the intrinsic size of the UILabel, you get a view that automatically resizes based on the text in the label.
Here's what the code looks like for the custom class. The .h file defines a single property text. The .m file has an IBOutlet to the child label. Setting and getting the text property simply sets or gets the text from the label. But there's one very important twist, setting the text invalidates the intrinsic size of the parent. That's what makes the system adjust the size of the parent view. In the sample code below the parent is sized to have an 8 pixel margin all around the UILabel.
SurroundView.h
#interface SurroundView : UIView
#property (strong, nonatomic) NSString *text;
#end
SurroundView.m
#interface SurroundView()
#property (weak, nonatomic) IBOutlet UILabel *childLabel;
#end
#implementation SurroundView
- (void)setText:(NSString *)text
{
self.childLabel.text = text;
[self invalidateIntrinsicContentSize];
}
- (NSString *)text
{
return( self.childLabel.text );
}
- (CGSize)intrinsicContentSize
{
CGSize size = self.childLabel.intrinsicContentSize;
size.height += 16;
size.width += 16;
return( size );
}
#end
Creating the IBOutlet to the childLabel can be a little tricky, so here's the procedure
drag out a UIView into the storyboard
use the Identity inspector to change the class to SurroundView
drag out a UILabel and add it as a subview of the SurroundView
select the label, and open the assistant editor
show SurroundView.m in the assistant
drag from the open circle to the label as shown below
All that's left is to get the constraints right. The constraints for the label should look like this
The constraints for the SurroundView should be as shown below. The key point is that the Intrinsic Size should be set to Placeholder to avoid the warnings about missing constraints.
Place the label inside the view and pin its TOP , BOTTOM , TRAILING and LEADING edges to the labels superview. Note that you do not specify the width constraint. Now add a height and width constraint to the view. Make an outlet to the width constraint and when the price changes set the view's width constraint's constant to your desired value. Since the label is pinned to the view it will expand too.

UIView animated changes with auto layout constraints

Say that I have a project which looks like the following:
There are two UIViews - one called yellowBox and the other called redBox. The auto layout constraints dictate that the yellowBox is 60 points from the top of the superview with 350 points leading and trailing spaces (i.e. to left and right of the view). The redBox has the same leading and trailing space constraints. There is a vertical space constraint between the two boxes of 0 to indicate that the bottom of the yellowBox should always be directly on top of the redBox.
When the user taps the Expand Yellow Box button, I would like the height of the yellowBox to increase and, as a result, the redBox moves down to continue satisfying the vertical space constraint (that the yellowBox is always on top of the redBox). Here is the animation code:
- (IBAction)expandYellowBox:(id)sender {
[UIView animateWithDuration:0.5
animations:^{
CGRect newFrame = self.yellowBox.frame;
newFrame.size.height += 50;
self.yellowBox.frame = newFrame;
}];
}
However, I have been unable to get this working properly. As you can see by the red icon, there is a problem with the constraints at the moment:
which is fair enough, as there's no way for auto layout to know the height of the boxes. However, I don't know how to resolve this issue in such a way that it will allow for the boxes to be resized and moved. For example, if I specify a height constraint on the yellowBox then that will prevent it from being resized. If I set the height constraint to be greater than or equal (to allow the yellowBox height to increase) then I get a different constraint error:
All constraints have been established using Xcode in the storyboard - none have been written in code.
Any help greatly appreciated.
EDIT: As it turns out, the yellowBox is growing when the button is clicked - it's just I couldn't tell because it appears behind the redBox. I only noticed after clicking it around four times and it started appearing out the bottom of the redBox. However, the same question still remains - how to get the redBox to always stick to the bottom of the yellowBox.
Try it as mentioned by shwet-solanki, but add the following line after changing the constraint:
[self.view layoutIfNeeded];
the IBAction would look like:
- (IBAction)expandYellowBox:(id)sender {
[UIView animateWithDuration:0.5
animations:^{
self.yellowBoxHeightConstraint.constant += 50;
[self.view layoutIfNeeded];
}];
}
Where yellowBoxHeightConstraint is the IBOutlet for height constraint of yellowBox.
Hope this helps.
Add Height constraint to both the views
Create an IBOutlet for height constraint of yellowbox
Now instead of changing the height of yellowbox in the button pressed event, rather change the value of the height constraint. i.e suppose your IBOutlet constraint name is yellowBoxHeightConstraint, then yellowBoxHeightConstraint.constant += 50;
Hope this works for you.
//
// WPViewController.h
// AutoLayoutTEst
//
// Created by VASANTH K on 09/01/14.
//
//
#import <UIKit/UIKit.h>
#interface WPViewController : UIViewController
#property (strong, nonatomic) IBOutlet UIButton *button1;
- (IBAction)buttClicked:(id)sender;
#property (strong, nonatomic) IBOutlet NSLayoutConstraint *heightConstrain;
#property (strong, nonatomic) IBOutlet UIButton *button2;
#end
click Event
- (IBAction)buttClicked:(id)sender {
self.heightConstrain.constant=100;
}
here u need to set the heightConstrain for the Yellow button then create reference outlet for that button then update the heightConstrain to update the size of that button it will automatically move your Red button down.
https://github.com/vasanth3008/AutoLayoutHeighDemo
refer my sample demo project

Resources