How to change uiview's height using auto layout? - ios

So I created this scenario in order to understand how views increase in height according to their content. However am still not able to make it happen.
This is what I have now:
the textview is growing according to content. however the uiview containing it is disappearing. what constraints should I use so that when the uitextview becomes bigger, its parent view also increase in height?

Start by clearing all your constraints from everything so we have a fresh slate.
Step 1: Build your view hierarchy. In this example, we want something like this:
The view controller's view, which we'll call parentView has a subview, which we'll call redView. That redView has a child, a Text Field, which we'll call textField.
The hierarchy looks like this:
Step 2: Set any constraints that are specific to any individual view. In this case, we probably only want to set a width constraint on our text view. For now, I'll just set a width of 200pts.
Step 3: Set the constraints between textView and its parent, redView. Let's say we want a 10pt border all the way around. Let's add these constraints:
Once we've added these constraints we'll gets some auto layout warnings and errors. For starters, because the constraints I added for with and space to superview don't match the actual sizes, I'll get some warnings like this:
There will also be some errors describing missing X and Y positions for redView and for textView. There are really twice as many errors here as necessary. textView knows where to position itself relative to redView. We don't need more constraints to sort out textView's position. However, redView doesn't know where to position itself yet... and so ultimately, textView also sort of doesn't exactly know.
We can update the textView's frame to get rid of the warnings, but let's go ahead and fix the actual errors.
Step 5: Set up redView's constraints relative to the superView. redView already know what size to be. Notice we had no errors for redView's width. It just doesn't know where to be. In this case, I'll go simple and say we want redView to be centered. So we'll want to add these constraints:
Now we've fixed some of the problems. The only problem that remains is the height for everything.
To fix this, we must set the content sizing priorities of textView. Set these all to 1000 and change the "Intrinsic Size" property to "Placeholder".
By now, all of the auto layout errors should be gone and we should only be left with warnings because our storyboard frames don't match what our constraints say they should.
We can fix that by selecting parentView and updating all the frames:
There's one final caveat to this auto layout puzzle when it comes to autosizing based on content size: what happens if our text view has no content?
If our textview has no content, auto layout will choose a height of 0, and our users won't even be able to see that there's a text view there, much less tap in it to add content (and make it expand). When using auto layout and content-based sizing, we should almost always be sure that we've set either an explicit or minimum size for the content view.
We don't have to worry about our textView's width, as we set this explicitly to 200. So let's add a minimum height constraint. Start by adding any height constraint:
Now go to the size inspector for the textView, find this height constraint we added, and edit it into a greater than or equal to constraint:
Storyboard won't reflect the change in content in our textView and resize it appropriately, but your constraints are now set up correctly and this will behave appropriately on your device or in the simulator.

ON UITextView make your you unselected These
Scrolling Enabled
Bounces
Bounce Horizontally
Bounce Vertically
Shows Horizontal Indicator
Shows vertical indicator
Now Change your auto layout constraints like this.

On the Storyboard Page, click on your textview.
Then click on the small triangular in the lower right corner.
Click first on "Clear Constraints".
An then on "Add Missing Constraints".
Its the easiest way.

Related

How to automatically have content size increase in UIScrollView on an action with autolayout?

I've setup a test project (project here) for this question to better illustrate my question, but here is the core issue I'm facing:
I have a UILabel nested within a content UIView which is itself nested inside a UIScrollView, and this is all laid out with AutoLayout. My initial layout works great, and the label is properly truncated to fit within it's content view as desired by the initial layout constraints. All is good so far.
Now the issue is when I want to add an "expand" action on the label. Let's say any tap on the content view should expand the label such that there is no longer truncation, and instead of truncating inside the contentView's bounds I want the scrollView's contentSize to increase such that the full label's text can now be scrolled. How should I accomplish this?
In the sample project, a tap on the content view will adjust the entire scrollView's constraints just to illustrate that the label now has a different amount of space to work with. I'm stuck as to how to now have the scrollView recalculate it's contentSize such that the label no longer truncates.
I've tried playing with content compression priority, and changing that based on the action being done, like so:
theLabel.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical)
But this doesn't seem to actually enforce that the label isn't going to truncate. I've also tried invalidating the intrinsic content size of the scrollView on the tap action, but to no avail. How do I toggle whether or not the label should truncate?
Generally you have a constraint which pins the height of the label or the view to your minimum height and when you want to expand you disable it (make it inactive) and layout the view. To compress re-enable the constraint and layout the view.

Swift - Why ScrollView not full screen?

I had inserted a ScrollView into UIViewController and dragged ScrollView to fill the space between the navigation bar and the RAM label below:
But when I run the app, the ScrollView does not fill the space:
Please help me! Thank you very much.
P/S: Sorry for my english is bad.
The scroll view is not covering up the whole thing because you are running the app on a much bigger phone. The simplest solution is to run the app on iPhone 5.
However, if you want to solve the problem on all sizes of iOS device, you need to add constraints.
Constraints are things that tells a view when and how much it should resize and where it should be positioned.
To add a constraint, just select the view you wish to add a constraint to and go to the bottom right corner. You will see 4 buttons:
The leftmost button is used to embedding views in stack views. This is a feature of iOS 9. If your deployment target is lower, just ignore it.
The second button to the left is for adding constraints related to alignment - where the edges of the views are, what its baseline is and where it is positioned in the X and Y axes:
The third button to the left is used to add constraint related to margins, width, height and how the width and height should change when it is asked to resize (keep the aspect ratio, for example):
The rightmost button is used to let Xcode decide what constraints you should add. And I think most of the times its choices are okay. Sometimes though, you still need to do some tweaking before it works.
"So... what constraints should I add?" you asked.
Well, I think I should teach you how to think when you want to add a constraint. This way, you can figure it out yourself in the future.
You should first let Xcode guess what constraints you want. Just click the rightmost button and click "Reset to Suggested Constraints". This can save a lot of work if Xcode can get it right. So remember to always do this first.
Then, run your app on various devices and see if the view's position, size, and alignment are as you expected. If it is not, you might have to add and/or remove some constraints.
For example, if you found that your view is always the same size on different devices, (that could be bad because it means that some content my go out of view on smaller devices) it's probably because Xcode added a width and/or height constraint to the view. You should delete that so that the view's width and/or height is not fixed.
You can find your view's constraints in the view hierarchy:
Just select the constraint and press delete.
Uncheck Adjust subview option and add
scrollview.view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
You need to add constraints for your scrollView. Set the leading and trailing constraints to 0. Pin the height of your scrollView and also don't forget to set the top layout constraint. You can either pin the height or add bottom layout constraint to your page control.
Constraints are very important and its even more important to set it correctly. Check the Apple Documentation - Working with constraints in IB
Uncheck constrain to margins and add 0 every one of the four limits of spacing to nearest neighbour.
My guess (from the little information we have) is that you are creating a constraint from your scrollview to the top of your view with a value equal to the height of the navigation bar. Set the value of this constraint to 0.
Just set the 4 constraints to 0 to the area you need and then uncheck the "Content Layout Guides" checkbox in the constraints tab here. It will automatically adjust to the area you have specified.
The checkbox to uncheck

Constraints in ios

I am learning constraints and spent whole day applying them to the following screen.It is not getting displayed properly in landscape mode.Basically i am not getting how to fix vertical space between ,say, label-Welcome to BBBB and textfield-username so that textfield always appears below the label yet the spacing between them is adjusted according to the screens of different size. If i go for Pin\Vertical space, it automatically fixes the constant value.
Remove the label (or just move it out of the way).
Fill the space that you want to resize with a view.
Constrain this view to the objects above and below and to the sides of the parent view.
Put your label into this view and constrain it to the top of this view and centred to it.
You may need to change the constraints on the objects above and below it to stop them from changing height in an unwanted manner.
This new view should now resize as the device changes orientation but the label should remain at the top of it.
Repeat on other areas of your layout (i.e put things that are not moving around as you want them into sub views and constrain these views to resize accordingly). Experiment with using variable heights, fixed heigh constraints and 'equal heights with' constraints on the views that you add to get them to resize as you need.
Edit: but you have a lot of vertically stacked items in that view - you may never get them all to fit into a horizontal orientation. You may need to remove a few, or add a scroll view or force that view only to layout in portrait mode or... Don't forget to check that it works on all devices you are targeting.
#Ali Beadle was right. Since i had a lot of vertically stacked items, lining them up in landscape mode was not possible. So, i went for scrollview.
I have taken a ScrollView first and then a UIView named ContentView on that ScrollView. I have made the width of ContentView equal to the width of parent UIView and kept its height fixed to 568. In my code i set
_contentViewHeight.constant = self.view.frame.size.height;
Now it scrolls in landscape mode while in potrait mode, it does'nt scroll.
I run into Autolayout problems all the time. But I finally figured out a way to overcome a lot of issues that arise from it.
I simply will use a container-View like ScrollView or even a plain old UIView, place all my controls in it. thats it. this makes things a lot easier for autolayout to figure out the constraints. in your case you could just use a UIView.
-start off by removing all the constraints you have I would start by selecting each control in the XIB and see if it has width/height constraint, select it then press the delete key then at the bottom of the project explorer you'll see all the constraints that auto layout has select each one then delete. that should get rid of any complaints that auto-layout might have.
-Place a UIView object inside your main View then
-move all the controls inside it. Then
-add the necessary constraints for the container view so it'll resize in different orientations and don't worry about any constraints inside the container view (auto layout will figure them out automatically).
that does the trick for me usually.

iOS and interface builder: misplaced view (e.g. UITableViewCell)

I am using interface builder to create a masterview details application. However
when I run the app the cell gets misaligned.
Here is how it looks both on the simulator and on interace builder:
Any suggestion on how to fix this?
I have noticed that this happens also in the detail view controller that's why I choose the title of "misplaced view":
The problem in the first screen shot seems to be that you are not supplying a tall enough height for the cell. Thus some of the views on one cell are actually appearing on top of the cell below it. You need to fix your table view's rowHeight.
In the second screen shot, it looks like you are using auto layout but you are not doing auto layout (you have no constraints). You need to position these interface elements with constraints.
Check your constraints in interface builder first and make sure that your UITableViewDelegate is returning the correct heightForRowAtIndexPath:, then report back.
In Interface Builder, if you select one of these views that is not sized correct and then select the "size inspector" tab on the panel on the right (option+command+5), if you have no constraints defined, IB will warn you:
The selected views have no constraints. At build time, explicit left, top, width, and height constraints will be generated for the view.
If you don't see that sort of message, your screen snapshots suggest that you likely have constraints defined for the view which are tantamount to the same thing, left/top/width/height constraints.
The problem is that when you transition to a real device with different width, the layout of the view will not be correct.
If, however, you defined your own constraints (for example, notably using trailing constraint instead of width constraint, using bottom constraint rather than height constraint), you'll find the views will be better adjusted for the device's actual dimensions.
In your first example, iOS 8 will automatically adjust the row height of the cell if you had defined constraints. Something like:
V:|-[nameLabel]-[artistLabel]-[categoryLabel]-[priceLabel]-|
V:|-[imageView]-|
H:|-[imageView(100)]-[nameLabel]-|
H:[imageView]-[artistLabel]-|
H:[imageView]-[categoryLabel]-|
H:[imageView]-[priceLabel]-|
I'm showing it to you in VFL, but you can define it in IB, too. The key point is add constraints so that the vertical height is now unambiguous (i.e. the cell height will be adjusted to fit the labels) and the width is not hard coded, but rather the labels will expand/contract to fill it depending upon the device size.
Conceptually the exact same problem occurs in your second example, that you don't have leading and trailing constraints, but rather IB has defaulted to using leading and width constraints, which will not work as you go from device to device. For example, if you just want the text view, but have it adjust for the size of the device's screen, you might have constraints equivalent to the following VFL.
H:|-[textView]-|
V:|-[textView]-|

resize superview after subviews change dynamically using autolayout

I cant for the love of god the the hang of this resizing superview.
I have a UIView *superview with 4 UILabels. 2 function as header for the 2 others.
The content in all 4 are dynamic coming from database.
SizeToFit vs SizeThatFits:(CGSize) vs UIView systemLayoutSizeFittingSize:, passing either UILayoutFittingCompressedSize or UILayoutFittingExpandedSize.
I use autolayout programatically and have set the superview height to be equal or greater to a dummy number.
where and how do I use these SizeToFit vs sizeThatFits:(CGSize) vs UIView systemLayoutSizeFittingSize:, passing either UILayoutFittingCompressedSize or UILayoutFittingExpandedSize. I have read a lot of tips here on stack but ended up with nothing.
DO I need to recalculate the constraints for the superview somewhere specific. Maby setting the height to be ยด#property` in its controller class and remove and readd it?
Atm I have tried to put everything everywhere and then some. Still I get the same size end result with the dummy height and text floating outside. Even after setting clipsToBound on subview.
I am scratching my hair of.. help
If you're using Auto Layout, here's what you need to do:
Make sure you aren't adding fixed width and/or height constraints to any of your subviews (depending on which dimension(s) you want to dynamically size). The idea is to let the intrinsic content size of each subview determine the subview's height. UILabels come with 4 automatic implicit constraints which will (with less than Required priority) attempt to keep the label's frame at the exact size required to fit all the text inside.
Make sure that the edges of each label are connected rigidly (with Required priority constraints) to the edges of each other and their superview. You want to make sure that if you imagine one of the labels growing in size, this would force the other labels to make room for it and most importantly force the superview to expand as well.
Only add constraints to the superview to set its position, not size (at least, not for the dimension(s) you want it to size dynamically). Remember that if you set the internal constraints up correctly, its size will be determined by the sizes of all the subviews, since its edges are connected to theirs in some fashion.
That's it. You don't need to call sizeToFit or systemLayoutSizeFittingSize: to get this to work, just load your views and set the text and that should be it. The system layout engine will do the calculations for you to solve your constraints. (If anything, you might need to call setNeedsLayout on the superview...but this shouldn't be required.)
Use container views
In the following example I have a 30x30 image, and the UILabel is smaller than the containing view with the placeholder text. I needed the containing view to be at least as big as the image, but it needed to grow to contain multi-line text.
In visual format the inner container looks like this:
H:|-(15.0)-[image(30.0)]-(15.0)-[label]-(15.0)-|
V:|[image(30.0)]|
V:|[label(>=30.0)]|
Then, set the containing view to match the height of the label. Now the containing view will ride the size of the label.
As #smileyborg pointed out in his answer, connecting the content rigidly to the superview informs the layout engine that the simple container view should cause it to grow.
Yellow alignment rectangles
If you want the yellow alignment rectangles add -UIViewShowAlignmentRects YES in your scheme's list of run arguments.
This almost follows #smileyborg answer and comes with a concrete example.
Won't describe all constraints, but those related to the calculation of the height of UI objects.
[Label] Labels must not have a fixed height constraint, in this case, AutoLayout won't resize labels to fit the text, so setting edge constraints is the key. (green arrows)
[Subview] Steps 1 and 3 are very easy to follow, but this step can be misunderstood. As in the case with labels, subviews must not have height constraint set. All subviews must have top constraint set, ignoring bottom constraint, which can make you think will trigger unsatisfied constraint exception at runtime, but it won't if you set bottom constraint for the last subview. Missing to do so will blow the layout. (red arrows)
[Superview] Set all constraints the way you need, but pay big attention to the
height constraint. Assign it a random value, but make it optional, AutoLayout will set the height exactly to fit the subviews. (blue arrows)
This works perfectly, there is no need to call any additional system-layout update methods.
This was made dramatically easier with the introduction of Stack Views in iOS 9. Use a stack view inside your view to contain all your content that resizes, and then simply call
view.setNeedsUpdateConstraints()
view.updateConstraintsIfNeeded()
view.setNeedsLayout()
view.layoutIfNeeded()
after changing your content. Then you can get your new size by calling
view.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
if you ever need to calculate the exact size required for a view.

Resources