I defined a view which contains an UImageView and a UILabel. I setted constraints for each elements.
In wanted to do a circle with the first view, so I did that in the code :
self.mainView.layer.cornerRadius = self.mainView.frame.size.width / 2;
self.mainView.clipsToBounds = YES;
So it works, I have a circle, BUT the UImageView and the UILabel seems don't follow the constraints setted in the storyboard.
For example, on my UILabel, I setted a margin left and right 5px to the mainView, but I can see my UILabel "out" the mainView....
I tried to do a "setNeedsUpdateConstraints", but it's not the solution.
So, what I need to do to have my UILabel correctly positioned ?
Thanks,
I think this is what you are looking for:
self.mainView.layer.masksToBounds = YES;
Your problem is that when changing the mainView's layer you are not actually changing the bounds of the view. The bounds of the view are still represented in a rectangle manner. what you need to do is change the width constraint of the UILable.
To do so just create a autolayout constrain to your UILable (is you don't have it already). Control-Drag it to your viewController and change it dynamically using the constant value in the constraint.
If you don't need to set it dynamically just set the left & right margins to a bigger margin
Related
I don't want to set a Y position constraint because I need the views to be relative to each other, since I have a UITextView that has to and should dynamically change its value based on how many lines of text are in it. It does not do this though. I can FORCE it to do it by calling sizeToFit() on the UITextView, but then it overlaps the views below.
Xcode nags me to reduce ambiguity and there are red lines all over the view controller, but it doesn't make any sense for me to manually have a Y position constraint if that has to be dynamic.
So my question is how do I
1. Make my UITextView resize its height after the number of lines of text increases
2. Make the views below it get pushed down automatically so the UITextView does not overlap them.
I've read multiple answers and have managed to do 1 but not the other.
Solution in Swift:
let sizeThatFitsTextView = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, textView.frame.size.height))
textViewHeightConstraint.constant = sizeThatFitsTextView.height
1) Disable the scroll of Textview from storyboard or by coding.
2) Create an outlet for textview's height constraint. Change the height constraint programmatically from textView delegate method when text change occur based on calculation.
CGSize sizeThatFitsTextView = [TextView sizeThatFits:CGSizeMake(TextView.frame.size.width, MAXFLOAT)];
TextViewHeightConstraint.constant = sizeThatFitsTextView.height;
I have two UILabel's. One UILabel is on the top of other. What I want is, if there is no content in top one, the bottom one should take the origin of top.
I have to use Auto Layout on the screen. I tried using sizeToFit but that is not working. Bottom UILabel is still stuck at it's origin if there isn't no content in top UILabel.
Setting constraint for height will not work. The y position of second label will not get its correct Y axis value (It will shift upwards). I solve your problem by playing with vertical spacing constraint between two results.
Explanation:- Set the normal basic constraints for label plus vertical spacing constraint. When there is no text in upper label, then update the vertical spacing constraint as follows:-
verticalSpacingConstraintBetweenLabels.constant = -(KIntialVerticalSpacing + (KHeightOfLabel-KIntialVerticalSpacing));
I create a sample project for you. Source code is available at:-
https://www.dropbox.com/s/eq9hinnw4sdfltq/LabelSpacing.zip?dl=0
One alternative to that requirement is to make IBOutlet for the height of the upper label and set it to 0 whenever you don't want to show it. But keep in mind you have to set vertical spacing between upper and lower label. The lower label shouldn't have top margin to superview.
First drag both top constrains to UIViewController.
Second paste this code:
-(void) loadLabels{
_firstLabel.text=#"";
NSInteger heidFirstLabel = 20;
if(_firstLabel.text.length == 0){
_constrainTopFirstLabel.constant = 0 - heidFirstLabel;
_firstLabel.hidden = YES;
}else{
_constrainTopFirstLabel.constant = 8 ;
}
}
I always use this.
In iOS9 apple has introduces a new class UIStackView to solve this and other problems that we the developers were facing, using auto layout. If you are targeting iOS 9 and later, you should use this class.
If you are targeting versions before iOS 9, one of the many ways could be using intrinsic content size.
1.Subclass UILabel
2.Add a property that determines if this label is collapses or not
#property (nonatomic,assign) BOOL isLabelCollapsed;
3.Override its method intrinsicContentSize
- (CGSize)intrinsicContentSize {
if(self.isLabelCollapsed)
return CGSizeMake(0, 0);
else
return [super intrinsicContentSize];
}
4.Set you collapsable labels class as your custom class.
5.When needed, set your isLabelCollapsed property to YES and call invalidateIntrinsicContentSize on you collapsble label.
I have a screen layout where there are two resizable labels , which will contain multiline text. These labels are placed inside their parent views which intern are added to main contentView, main contentView is then added to scrollView ( thats what most of the solutions suggests). For both the labels (below About and Time and location labels in first image attached) I have set height constraints as "greater than or equal to" and setting the numberOfLines to 0 as well as calling SizetoFit, but actual output is not as expected (see second image attached). There are no constraints warnings. All constraints are provided for all the elements.
The code in viewDidLoad is as follows for one of the label.
self.lblAbout.text = #"this is a long two three lines about string which will have two lines this is a long two three lines about string which will have two lines";
self.lblAbout.numberOfLines = 0;
[self.lblAbout sizeToFit];
[self.lblAbout setPreferredMaxLayoutWidth:244.0];
Also
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
scrollView.contentSize = contentView.frame.size;
}
Not if any additional constraints are needed, I have added all leading , trailing , top , bottom constrains along with height wherever needed, plus the spacing between all the views is in place.
What i want is the labels should get adjusted to number of lines and the contentView (parent view) should scroll inside ScrollView as the total height will be larger than the screen available.
*** problem I think is the outer view of the labels aren't getting resized as per the label because of which all the views below it aren't getting repositioned ****
Please try this Solution,
1. add Height Constraint to superView of your Label.
2. add IBOutlet of that Constraint
3. add this Method to find out Height of your Text
you need to give width of super view of your Label so width will be same as your super view
4. Now get Height form returned CGRect and assign it to your Constraints's constant. it should be like
heightConstraint.constant = youObject.size.height;
please Make sure you have added other Constraints accordingly this. if not than you need to also increase Height of other superviews accordingly.
(CGRect)sizeOfDetailLabelFromString:(NSString*)string maxWidth:(CGFloat)maxWidth{
NSDictionary *attributes = #{NSFontAttributeName:FONT_LIGHT};
CGRect rect = [string boundingRectWithSize:CGSizeMake(maxWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:attributes context:nil];
return rect;
}
Here is what worked finally.
Added ScrollView in main View
Added View as a contentView ( be sure to rename it in designer to something than just view )
pinned scrollview to main view using leading trailing top and bottom space constraints.
Pinned contentView to scrollview same as above
Added all the components with their respective constraints
Set the height of UILabel which i want to resize using "Greater than or equal to constraint (this is necessary) and set number of lines to 0 in code
The parent view of label shouldn't have any fixed height but enough constraints to calculate it at runtime.
Make sure ScrollView has no ambiguity in calculating contentSize.
imp - Add constraints to width of Main view , scrollview , contentView ( that was in my case , you may not need equal width constraint between contentView and scrollview , but between contentView and main view its necessary)
Now scrollview scrolls exactly the way it's needed.
To my belief most of the above things i already did but somehow it wasn't working ,deleted everything and did all the things again few times and it worked.
I'm trying to make layout inside scrollview using this one tutorial link
And get the following result link
It will be appreciated for any advices or tutorial links. It needs only vertical scrolling
I am sure there must be other ways to do this but a quick fix is :
1.) Create a width constraint on ContentView in Storyborad.
2.) IBOutlet that widthContraint and set its value to the view frame width in viewDidLoad.
Suppose the name of the constraint outlet is contentViewWidthContraint.
contentViewWidthContraint.constant = self.view.bounds.size.width;
Another alternative to do so from Storyboard, is to fix the Contentview width to the view's width from the storyboard or to the Scrollview, if Scrollview already has a Equal width contraint with superview . Add the "Equal Width" contraint from Contentview to either self.view or to Scrollview (if scrollview, already has the width contraint)
Have you set up the "ContentView" width to match with the scroll view width? I had the same problem and I fixed with "Equal Widths".
"Equal Widths" will tell to your "ContentView" to use the same width of the "Scroll View", which should be fitting the screen if you have set up the constrain properly.
You can do this easily on the storyboard.
Drag and drop, with right click (important!!!), from "ContentView" to "ScrollView"
Release the click, you will be prompted with a menu, select "Equal Widths".
This should fix your problem using the scrollview with AutoLayout from Storyboard editor.
You can find a full tutorial how to use ScrollView with Autolayout and Storyboard here.
I hope this is useful for you :)
In the Storyboard set the width of the elements contained in your UIScrollView equal to the width of this UIScrollView (by selecting all elements and the UIScrollView holding in the panel on the left of your Storyboard and then setting the 'Equal Widths' constraint under 'Pin' on the bottom of your Storyboard). Just pinning the right sides of the elements to that of the UIScrollView won't work as it will adjust the size of its "display view" to the width of the largest element and if this is smaller than the width of the UIScrollView all elements will just appear aligned to its left side.
There is also another possibility that offers a very good result.
You can mark a checkbox:
O programmatically:
scrollView.alwaysBounceVertical = true
Try to set it's width to 0 & height equal to content size like this:
self.scrollView.contentSize = CGSizeMake(0, self.scrollView.contentSize.height);
This will work as you want. Try it & tell if still facing any issue.
For disabling the horizontal scroll, you can set the content size in the -(void)scrollViewDidScroll method.
[self.scrollView setContentOffset: CGPointMake(0, self.scrollView.contentOffset.y)];
self.scrollView.directionalLockEnabled = YES;
This is because scroll view have no idea where your content should end.
But when at least one item inside your scroll view has its "trailing space" constraint attached to a view outside the scroll view (usually a view the scroll view is sitting in or some other view of a higher level, which "knows" its width) - the scroll view will automatically get an idea about your wanted width and won't scroll horizontally (unless that trailing constraint implies having your content outside the screen).
Better if all items inside scroll view have their "trailing space" constraints connected either to each other or to a view outside the scroll view. But not the scroll view itself.
No additional code or extra constraints needed for this to work.
Too set UIScrollView constraints as like below code so it will occupied whole screen.Not exceed the screen size.
Leading Space = 0 from mainView
Top Space = 0 from mainView
Bottom Space = 0 from mainView
Trailing Space = 0 from mainView
You need to set the width of UIScrollView equal to or less than the width of your Parent View. Two ways to do it:
1) You can do this in Storyboard via layout constraints
2) You can do this programatically:
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, self.scrollView.contentSize.height);
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.