Recently I have been requested by my client to add a large title navigation bar into their app’s main screen, on top of that the large title should automatically collapse when users start scrolling.
I think to myself: how hard could this be? It is just a native iOS component, I should be able to get this done in no time!
Unfortunately, I was wrong.
In this article, I would like to share with you the UI and animation glitches that caught me off guard, and most importantly how I manage to fix them.
Before we get started, There are 2 things you should be aware of:
- The glitches that I am about to show you only happened in a
UIViewController
with a scrollable view (UITableView
,UICollectionView
orUIScrollView
) as a subview. If you are using anUITableViewController
orUICollectionViewController
, you won’t have to worry about all these glitches. - Throughout the article, I will be using
UICollectionView
as an example. However, you can apply the same concept toUITableView
andUIScrollView
as well.
With all that being said, let’s begin!
The Unwanted Snap and Drag Behavior
The first UI glitch that I would like to show you is this:
As seen from the above animated GIF, the navigation bar has an unnatural snapping behavior when transitioning from large title to small title. Furthermore, the large title navigation bar does not expand its height when I start dragging downward, causing the title to overlap with the collection view (the yellow color area).
If you are facing the same problem as mine, most probably you and I are having the same auto layout configuration as shown below.
As you can see, the collection view’s top constraint is aligned to the view controller’s top safe area layout guide and that is the root cause of the unwanted behaviors.
In order to solve the problem, all you need to do is to make the collection view’s top constraint align to the top of the view controller’s view.
Here’s how you can do it using code:
self.view.addSubview(collectionView)
collectionView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: self.view.topAnchor),
...
...
...
])
With this simple change, you should be able to fix the unwanted snap and drag behavior.
Large Title Navigation Bar Not Collapsing
Let’s say you have set up all the auto layout constraints correctly, but when you start scrolling the collection view, the large title navigation bar does not collapse.
What should you do?
Based on my investigation, in order for the large title navigation bar to work correctly, the collection view must be the first subview in the view controller’s z-axis.
Let’s say you have a view controller with only 2 subviews — a collection view and an activity indicator. If the activity indicator is located behind the collection view, the navigation bar will not collapse.
Therefore, to fix this glitch, just make sure that there are no other views behind the collection view, then you are good to go.
Do note that if the collection view is inside a container view, as long as the container view is the first subview in the view controller’s z-axis, everything should work correctly as well.
Large Title Navigation Bar with UIRefreshControl
Currently, there are 2 ways to add a UIRefreshControl
to a collection view. The first way is the standard way, where you directly assign a refresh control to the collection view.
let refreshControl = UIRefreshControl()
collectionView.refreshControl = refreshControl
Another less-standard way is to add the refresh control as a subview to the collection view.
let refreshControl = UIRefreshControl()
collectionView.addSubview(refreshControl)
Surprisingly, if the large title is enabled, both of these ways will result in different pull-to-refresh behavior. Let me show you what I mean.
If you are using the standard way, the refresh control will animate on top of the large title.
Whereas when using the less-standard way, the refresh control will animate below the large title.
Is this an animation glitch? I am not sure 😅. But still, I think this is an interesting discovery that is worth sharing.
Personally, I would suggest everyone to use the standard way because it is less hacky, which in other words means it is more future proof. Furthermore, the pull-to-refresh animation does look and feel more natural.
Bonus Trick: Styling the Large Title Navigation Bar
If you are using the large title navigation bar, most probably you will want to adjust its styling to suit your needs. This is where the UINavigationBarAppearance
APIs introduced in iOS 13 comes in handy.
For example, you can use the following code snippet to customize a specific view controller’s navigation bar font and background color.
let appearance = UINavigationBarAppearance()
// Set background color
appearance.backgroundColor = .systemTeal
// Set font
appearance.largeTitleTextAttributes = [
NSAttributedString.Key.font: UIFont.italicSystemFont(ofSize: 30)
]
appearance.titleTextAttributes = [
NSAttributedString.Key.font: UIFont.italicSystemFont(ofSize: 15)
]
// Apply the appearance
self.navigationController?.navigationBar.scrollEdgeAppearance = appearance
self.navigationController?.navigationBar.compactAppearance = appearance
self.navigationController?.navigationBar.standardAppearance = appearance
If you would like to change the navigation bar styling thoughtout the entire app, you can add the following code snippet to the application(_:didFinishLaunchingWithOptions:)
delegate method.
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = . systemTeal
appearance.largeTitleTextAttributes = [
NSAttributedString.Key.font: UIFont.italicSystemFont(ofSize: 30)
]
appearance.titleTextAttributes = [
NSAttributedString.Key.font: UIFont.italicSystemFont(ofSize: 15)
]
UINavigationBar.appearance().scrollEdgeAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().standardAppearance = appearance
Wrapping Up
Apple makes enabling the large title navigation bar extremely easy. However, getting it right is a little bit tricky. Therefore, next time if you bump into any unexpected glitches when using a large title navigation bar, remember to check the following:
- The scrollable content top constraint must align to the top of the view controller’s view.
- The scrollable content (or its container) must be the first subview in the view controller’s z-axis.
- If you are using a
UIRefreshControl
, make sure to use the standard way to assign it to the scrollable content.
Lastly, if the screen that you create is not complicated, you can always use the UITableViewController
and UICollectionViewController
to avoid any of these glitches.
If you enjoy reading this article, feel free to check out my other iOS development related articles. You can also follow me on Twitter, and subscribe to my monthly newsletter.
Thanks for reading. 👨🏻💻
👋🏻 Hey!
While you’re still here, why not check out some of my favorite Mac tools on Setapp? They will definitely help improve your day-to-day productivity. Additionally, doing so will also help support my work.
- ✨ Bartender: Superpower your menu bar and take full control over your menu bar items.
- ✨ CleanShot X: The best screen capture app I’ve ever used.
- ✨ PixelSnap: Measure on-screen elements with ease and precision.
- ✨ iStat Menus: Track CPU, GPU, sensors, and more, all in one convenient tool.