I am using autolayout for set height of uiview depends on it's subview.
I am using Reusable view.
I have added that view in my viewcontroller is here is code
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSArray *arrNib = [[NSBundle mainBundle] loadNibNamed:#"ReUsableView" owner:self options:nil];
UIView *subView = [arrNib objectAtIndex:0];
[self.view addSubview:subView];
lbl1 = [subView viewWithTag:1];
lbl1.text = #"fjadsk jkdjf kasdjf kasjdfkas djfkjads kfjaksd fjaskdjf kdsajf ksdjf ksdaj fksadjfkadsjf ksadjfksajd fkdsjfkajf kcnvmjkdalsjfk vaksdjfkj kfdvnkdsjfkajfkda djfkajsdfksja dfksjdafkjas;fjsk";
}
I got output like this
When I will remove bottom constaint of lbl first then I got following output.
How can I increase the height of uiview depends on lbl first height?
Appreciate for help!
Considering that you want to increase the size of your blue view with lbl, You have to do following things
Give the fixed height constraints to the lbl1.
Remove height constraint to container view.
Add equal height constraints to container view & lbl1
Change the multiplier property of equal widths constraints by
calculating containerView height / lbl1 height ("/" means divide by)
Take outlet of height constraints of lbl1.
Calculate the changed height of lbl1.Assign this to height
constraints of lbl by setting constraints.constant property.
to make this happen, required constraints for view is;
top=view.top
leading = view.leading
trailing = view.trailing
bottom >= view.bottom
lhs of equations belongs to superview of your view.
for label inside;
lbl.top = view.top
lbl.leading = view.leading
lbl.trailing = view.trailing
lbl.bottom = view.bottom.
i built it in storyboard; here is the screenshot. view size is getting bigger when the text inside the label is getting longer.
Related
I have a situation where i have following view layout.
-UIViewcontroller
-SCrollView
-UIView(outer)
-buttons
-labels
-UIView(inner)
-labels
-buttons
-buttons
the inner UIView height can be any longer as content inside is dynamically added.
So the main issue is i can not scroll till the end of the content, instead i can only scroll till the height of inner UIView.
NOTE - I am using auto layout
Any help is much appreciated.
Thanks
You should change the frame of your inner view dynamically based on the content you are adding. According to your inner view hierarchy, you have label and button. You might be setting some dynamic text on label and also doing some manipulation with button . Use the following method to get the height of the text ,
- (CGSize)getHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font {
CGSize size = CGSizeZero;
if (text) {
CGRect frame = [text boundingRectWithSize:CGSizeMake(widthValue, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{ NSFontAttributeName:font } context:nil];
size = CGSizeMake(frame.size.width, frame.size.height);
}
return size;
}
Here font is the font you set to button and label. Call this method by passing the text added on label and button. CGSize has a height property , add height value of label and button. Now set this sum height to innerView by calling innerView.frame.size.height = <height>. This increase the height of your innerView based on content inside that.
Put all your buttons in the bottom inside a container view and add the following constraints to the outerView (assuming that the new container you've added is called "buttonContainer"):
A vertical spacing constraint between the bottom of innerView and the top of the buttonContainer.
A vertical spacing constraint between the bottom of the buttonContainer and the bottom of the outerView.
Horizontal spacing constraints between between the buttonContainer and outerView to force it to full width.
When using AutoLayout, you have to have enough constraints to properly define the contentSize of the scrollView.
For more information about using AutoLayout with UIScrollView, check out the following links by Apple:
Working with Scroll Views
UIScrollView and Autolayout
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 have a UIView containing a UILabel made in an Interface Builder .xib file. The label text is set from code and I want the UIView and UILabel to resize to fit the text using auto layout.
Label configuration:
Pinned width 320
Number of lines 0
Leading space to superview 0
Bottom space to superview 0
Trailing space to superview 0
The view is loaded like this:
MyView *myView = [[[NSBundle mainBundle] loadNibNamed:#"MyView" owner:self options:nil] objectAtIndex:0];
myView.myLabel.text = #"My short or long text";
and I use it as a table header:
[self.tableView setTableHeaderView:myView];
The view does not resize, it stays one line truncated with ... at the end. How do I get it to resize?
I tried increasing vertical content hugging and content resistance for the label, I tried adding a low priority height constraint, I tried setPreferredMaxLayoutWidth, all without luck.
Note: This is a simplified example. I will need more elements in the view, and I would like to avoid calculating every coordinate manually based on the label's sizeWithFont. It's my understanding that auto layout should be the holy grail for this.
CGSize maximumSize = CGSizeMake(maxWidthOfYourLabel, 9999);
UIFont *myFont = label.font;
CGSize myStringSize = [yourString sizeWithFont:myFont constrainedToSize:maximumSize lineBreakMode:NSLineBreakByWordWrapping];
label.frame = CGRectMake (label.frame.origin.x, label.frame.origin.y, myStringSize.width, myStringSize.height);
yourView.height = label.height;
This is the only way i know and this involves sizeWithFont:
I doubt UITableView will play nicely with your view if you are resizing its header with autolayout. The way we work with dynamic-sized table headers (or footers) is like this:
Compute and resize the header view's frame.
Re-set the header via self.tableView.tableHeaderView = myView;
Step 2 is the key. You have to set tableHeaderView again even if the same view will be applied. I understand that having to play with frames in an autolayout paradigm is very ugly, but you may not have to if you find the proper method to put self.tableView.tableHeaderView = myView;.
I just come across the same problem like you.
What I do is like this:
//Init headerView from nib file
//Set the content to show
[headerView setupWith:somethingToShow];
headerView.height = [headerView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
self.tableView.tableHeaderView = headerView;
Consider a UIScrollView with a single subview. The subview is an UIImageView with the following size constraints:
Its height must be equal to the height of the UIScrollView.
Its width must be the width of the image scaled proportionally to the height of the UIImageView.
It is expected that the width of the UIImageView will be bigger than the width of the UIScrollView, hence the need for scrolling.
The image might be set during viewDidLoad (if cached) or asynchronously.
How do you implement the above using autolayout, making as much use as possible of Interface builder?
What I've done so far
Based on this answer I configured my nib like this:
The UIScrollView is pinned to the edges of its superview.
The UIImageView is pinned to the edges of the UIScrollView.
The UIImageView has a placeholder intrinsic size (to avoid the Scrollable Content Size Ambiguity error)
As expected, the result is that the UIImageView is sized to the size of the UIImage, and the UIScrollView scrolls horizontally and vertically (as the image is bigger than the UIScrollView).
Then I tried various things which didn't work:
After loading the image manually set the frame of UIImageView.
Add a constraint for the width of the UIImageView and modify its value after the image has been loaded. This makes the image even bigger (?!).
Set zoomScale after the image is loaded. Has no visible effect.
Without autolayout
The following code does exactly as I want, albeit without autolayout or interface builder.
- (void)viewDidLoad
{
{
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:scrollView];
self.scrollView = scrollView;
}
{
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height)];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.scrollView addSubview:imageView];
self.scrollView.contentSize = imageView.frame.size;
self.imageView = imageView;
}
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[self layoutStripImageView];
}
- (void)layoutStripImageView
{ // Also called when the image finishes loading
UIImage *image = self.imageView.image;
if (! image) return;
const CGSize imageSize = image.size;
const CGFloat vh = self.scrollView.frame.size.height;
const CGFloat scale = vh / imageSize.height;
const CGFloat vw = imageSize.width * scale;
CGSize imageViewSize = CGSizeMake(vw, vh);
self.imageView.frame = CGRectMake(0, 0, imageViewSize.width, imageViewSize.height);
self.scrollView.contentSize = imageViewSize;
}
I'm trying really hard to move to autolayout but it's not being easy.
Under the autolayout regime, ideally the UIScrollView contentSize is solely determined by the constraints and not set explicitly in code.
So in your case:
Create constraints to pin the subview to the UIScrollView. The constraints have to ensure the margin between the subview and the scroll view are 0. I see that you have already tried this.
Create a height and a width constraint for your subview. Otherwise, the intrinsic size of the UIImageView determines its height and width. At design time, this size is only a placeholder to keep Interface Builder happy. At run time, it will be set to the actual image size, but this is not what you want.
During viewDidLayoutSubviews, update the constraints to be actual content size. You can either do this directly by changing the constant property of the height and width constraint, or calling setNeedsUpdateConstraints and overriding updateConstraints to do the same.
This ensures that the system can derive contentSize solely from constraints.
I've done the above and it works reliably on iOS 6 and 7 with a UIScrollView and a custom subview, so it should work for UIImageView too. In particular if you don't pin the subview to the scroll view, zooming will be jittery in iOS 6.
You may also try creating height and width constraints that directly reference a multiple of the height and width of the scroll view, but I haven't tried this other approach.
translatesAutoresizingMaskIntoConstraints is only required when you instantiate the view in the code. If you instantiate it in the IB it's disabled by default
In my opinion the UIImageView should fill the ScrollView. Later I'd try setting the zoom of the scrollview to the value that suits you well so the image can only be panned in one direction
In my case it was a full width UIImageView the had a defined height constraint that causing the problem.
I set another constraint on the UIImageView for the width that matched the width of the UIScrollView as it is in interface builder then added an outlet to the UIViewController:
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *imageViewWidthConstraint;
then on viewDidLayoutSubviews I updated the constraint:
- (void) viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.imageViewWidthConstraint.constant = CGRectGetWidth(self.scrollView.frame);
}
This seemed to do the trick.
I'd like to have some views fixed on the top of the screen,
some other on the bottom and a single fixed size view in the equal distance between the top and bottom views.
I cannot figure out how to do this with Autolayout constraints. Do I need to add some spacer views to the UI, or calculate the desired position programatically?
You can do this with only one additional view. It'd look like this:
stuff_on_top
middle_view (with fixed size view inside)
stuff_on_bottom
There'd be vertical spacing constraints between stuff_on_top & middle_view and between middle_view & stuff_on_bottom. fixed size view would be centered horizontally and vertically in middle_view.
The other way of doing this would be two put two spacer views: between stuff_on_top & middle_view and between middle_view & stuff_on_bottom. Then you'd add a constraint that heights of spacing views are equal.
Check out this category: https://github.com/jrturton/UIView-Autolayout
Then you can do something as simple as this...
#import "UIView+AutoLayout.h"
...
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *topView = [UIView autoLayoutView];
UIView *centralContainerView = [UIView autoLayoutView];
UIView *centralView = [UIView autoLayoutView];
UIView *bottomView = [UIView autoLayoutView];
topView.backgroundColor = [UIColor redColor];
bottomView.backgroundColor = [UIColor redColor];
centralView.backgroundColor = [UIColor greenColor];
[self.view addSubview:topView];
[self.view addSubview:centralContainerView];
[centralContainerView addSubview:centralView];
[self.view addSubview:bottomView];
//Pins the topView to the top, left and right edges of its superview (in iOS 7, it uses the topLayoutGuide)
[topView pinToSuperviewEdges:JRTViewPinTopEdge|JRTViewPinLeftEdge|JRTViewPinRightEdge inset:0 usingLayoutGuidesFrom:self];
//Constrains the height of topView to 75pts (if a value is passed as zero, no constrain is applied to that axis)
[topView constrainToSize:CGSizeMake(0, 75)];
//Pins the centralContainerView to the left and right edges of its superview
[centralContainerView pinToSuperviewEdges:JRTViewPinLeftEdge|JRTViewPinRightEdge inset:0];
//Pins the top of centralContainerView to the bottom of topView
[centralContainerView pinEdge:NSLayoutAttributeTop toEdge:NSLayoutAttributeBottom ofItem:topView];
//Pins the bottom of centralContainerView to the top of bottomView
[centralContainerView pinEdge:NSLayoutAttributeBottom toEdge:NSLayoutAttributeTop ofItem:bottomView];
//Centers centralView on the Y axis of its superview
[centralView centerInContainerOnAxis:NSLayoutAttributeCenterY];
//Pins the centralView to the left and right edges of its superview
[centralView pinToSuperviewEdges:JRTViewPinLeftEdge|JRTViewPinRightEdge inset:0];
//Constrains the height of topView to 100pts
[centralView constrainToSize:CGSizeMake(0, 100)];
//Pins the topView to the bottom, left and right edges of its superview (in iOS 7, it uses the bottomLayoutGuide)
[bottomView pinToSuperviewEdges:JRTViewPinBottomEdge|JRTViewPinLeftEdge|JRTViewPinRightEdge inset:0 usingLayoutGuidesFrom:self];
//Constrains the height of topView to 75pts
[bottomView constrainToSize:CGSizeMake(0, 75)];
}
And you get an output like this:
Edit:
I didn't see the interface-builder tag and just jumped to conclusions... An interface builder alternative would work similar to above.. You would need to have three main views, one pinned to the top and the other pinned to the bottom.. Then one with a flexible width that is pinned to the other two views.
You can then centre a fourth view with a fixed height in your middle view. This will then give you the result you are looking for
I code this
https://github.com/damienromito/UIView-AutoYPositioning
But I think a solution with AutoLayout exist...