How to constrain height for ScrollView with dynamic content inside? - ios

We are trying to resolve the warning for ScrollView "needs constraint for y position or height"
The scrollView has
a card View which has dynamic content inside, e.g. various text that expands with accessibility
a tableview with undetermined number of cells whose content can also expand with accessibility
So far we can only put >= height constraint for the tableView/cardView, but the scrollView doesn't know the exact height of its subcomponents so it can't calculate itself.
However, even with the warning, it does run fine and as expected.
An alternative strategy we've tried is to put an explicit height on the the tableView, let's say 500, then when the view has loaded, get the calculated content size and set height = actual content size.
Is there a better way to handle height constraints for ScrollView with dynamic content inside?

DonMag is right. I was not aware of the Intrinsic Size: PlaceHolder but that is the exact solution to my problem.
For those looking, it will be at the bottom of the Size Inspector, the second last IB Inspectors pane.
This topic should help anyone else:
What is the difference of intrinsic size vs system width/height constraints?

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.

How to change uiview's height using auto layout?

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.

Using autolayout to manage height of UILabel within a subview

Using Xcode 5, interface builder and developing for iOS 7.
Within my content view I have 2 additional sub views, one on top of another. Within the upper subview I have a UILabel. I would like for that UILabel to expand in height when the content exceeds the first line, but I can't seem to get the height increase of the UILabel to increase the height of the subview, thus pushing the bottom subview down the main content view.
Additionally, I would assume the content view would need some sort of a constraint that reflects the overall height of the two subviews?
Perhaps this the question has already been answered somewhere, but I've searched everywhere and can't seem to come up with a solution.
Any help would be hugely appreciated! Thanks in advance.
There is a couple of steps that you have to do to achieve this using autolayout.
Set layout constrains for the label.
Set height constraint with low priority.
Set numberOfLines to 0 to allow multiline text.
Set preferredMaxLayoutWidth for the label.
The preferredMaxLayoutWidth is used by label to calculate its height.
This property affects the size of the label when layout constraints
are applied to it. During layout, if the text extends beyond the width
specified by this property, the additional text is flowed to one or
more new lines, thereby increasing the height of the label.
Also, have a look here.

Setting constraints to UIScrollView

Need some help to set constraints to UIScrollView.
I tried to follow the instructions here: https://developer.apple.com/library/ios/technotes/tn2154/_index.html (Mixed approach).
Setting 4 sided constraints to UIScrollView.
Then set 4 sided constraints to the buttonContainer.
This the result:
However xcode is giving this error message:
If I try xcode's recommendation, either the scrollview will not scroll, or it doesn't display at all.
Any idea what's wrong here?
The messages you are getting tell you what to do. The scroll view sets its content size and becomes scrollable through the constraints pinning its subview(s) to the scroll view itself. Those constraints must therefore provide sufficient information. You have not provided enough internal constraints to describe the height and width of the scrollable area (the content size).
In other words, think of the constraints as sizing the buttonContainer from the inside out. That is what you have neglected to do. You can solve this, for instance, simply by giving the buttonContainer an absolute width constraint and an absolute height constraint. And those values need to be bigger than the size of the scroll view itself if the content is to be scrollable.

Autolayout constraints to make UILabel more sensitive to taps

I have 2 tappable labels grouped within a parent view (The attached screenshot shows 3 of these views). Currently the size of each label is set to fit its content. Therefore a tap gesture is only recognized when the tap is directly on the text. I want to be able to tap above or below the text (but within its parent view) so that a tapped label is triggered. What type of constraints would I need to add between the views so that I’m able to do this?
You could add minimum widths and heights to the labels, and that might do what you want (width >= minimum). Alternatively, you could add these labels as the child of a larger UIView that does the gesture recognition. You should add constraints to that UIView so that it expands as the UILabels expand, and again, you'd still need minimum widths and heights.
You would add a height constraint to each label. This is not normally needed, because a label has an intrinsic content size (intrinsicContentSize) that is used to generate its height automatically, through two low-priority constraints that cause the label to resist getting larger than or smaller than the intrinsic height. But if you simply add a height constraint, you can make the label taller, overriding the intrinsic content size; this works because your constraint has a higher priority than the intrinsic height constraints.

Resources