Challenge time!
Imagine we have 2 content views:
- UIView with dynamically height content (expandable UITextView) = RED
- UIView as a footer = BLUE
This content is inside a UIScrollView = GEEN
How should I structure and handle the constraints with auto-layout to archive all the following cases?
I am thinking next basic structure to start with:
- UIScrollView (with always bounce vertically)
- UIView - Container
- UIView - DynamicHeightContent
- UIView - Sticky Footer
Keyboard handling should be done by code watching notifications UIKeyboardWillShowNotification
and UIKeyboardWillHideNotification
. We can chose to set the keyboard's end frame height to Container UIView bottom pin constraint or to the UIScrollView bottom contentInset.
Now, the tricky part is the sticky footer.
- How we make sure the sticky footer UIView stays at the bottom if there is more screen available than the whole Container View?
- How do we know the available screen space when the keyboard is shown/hidden? we'll surely need it.
- Is is it right this structure I purpose?
Thank you.
Instead of using a
UIScrollView
you would very likely be better off with aUITableView
. It also might be better to not using auto-layout. At least, I've found it better to not use it for these sorts of manipulations.Look into the following:
UITextView textViewDidChange
sizeThatFits
(limiting width and using FLT_MAX for height). Change the frame, not the contentSize.UITableView
beginUpdates/endUpdates to update the table viewUIKeyboardWillShowNotification
notificationNSNotification
that comes through, you can call userInfo (a Dictionary), and the keyUIKeyboardFrameBeginUserInfoKey
. Reduce the frame of the table view based on the height of the size of the keyboard.UIKeyboardWillHideNotification
notificationTo have the footer view stick to the bottom, you could add an intermediate cell to the table view, and have it change size depending on the size of the text and whether the keyboard is visible.
The above will definitely require some extra manipulation on your part - I don't fully understand all of your cases, but it should definitely get you started.
If I understand whole task, my solution is put "red" and "blue" views to one container view, and in the moment when you know size of dynamic content (red) you can calculate size of container and set scrollView content size. Later, on keyboard events you can adjust white space between content and footer views
When the text content of the
UITextView
is relatively short, the content view's subviews (i.e., the text view and footer) will not be able to dictate the size of their content view through constraints. That's because when the text content is short, the content view's size will need to be determined by the scroll view's size.Update: The latter paragraph is untrue. You could install a fixed-height constraint either on the content view itself or somewhere in the content view's view hierarchy. The fixed-height constraint's constant could be set in code to reflect the height of the scroll view. The latter paragraph also reflects a fallacy in thinking. In a pure Auto Layout approach, the content view's subviews don't need to dictate the scroll view's
contentSize
; instead, it's the content view itself that ultimately must dictate thecontentSize
.Regardless, I decided to go with Apple's so-called "mixed approach" for using Auto Layout with
UIScrollView
(see Apple's Technical Note: https://developer.apple.com/library/ios/technotes/tn2154/_index.html)Some iOS technical writers, like Erica Sadun, prefer using the mixed approach in pretty much all situations ("iOS Auto Layout Demystified", 2nd Ed.).
In the mixed approach, the content view's frame and the scroll view's content size are explicitly set in code.
Here's the GitHub repo I created for this challenge: https://github.com/bilobatum/StickyFooterAutoLayoutChallenge. It's a working solution complete with animation of layout changes. It works on different sized devices. For simplicity, I disabled rotation to landscape.
For those who don't want to download and run the GitHub project, I have included some highlights below (for the complete implementation, you'll have to look at the GitHub project):
The content view is orange, the text view is gray, and the sticky footer is blue. The text is visible behind the status bar while scrolling. I don't actually like that, but it's fine for a demo.
The only view instantiated in storyboard is the scroll view, which is full-screen (i.e., underlaps status bar).
For testing purposes, I attached a double tap gesture recognizer to the blue footer for the purpose of dismissing the keyboard.
Although the Auto Layout component of this demo app took some time, I spent almost as much time on scrolling issues related to a
UITextView
being nested inside of aUIScrollView
.