Dynamic Type: Large Content Viewer
What is the Large Content Viewer?
Large Content Viewer is a feature introduced by Apple along Dynamic Type.
Most of the time, your content should grow according to the current Dynamic Type Size. But for some components, it can make sense to keep them at a default (small) size.
For example, components that are always on screen, such as status bars and tab bars.
Or components that are secondary to the content, such as navigation bars and toolbars.
They should be kept small in order to leave the available screen space to the primary content.
But we still need to make sure those components stay readable.
For that, Large Content Viewer comes into place!
If one of the 5 Accessibility Dynamic Type Sizes is selected → when the user puts his finger on an element such as a tab bar or navigation bar → a popup (or “Large Content Viewer”) is displayed:
When should we use Large Content Viewer on our custom components?
It will depend, but generally on cases similar to Apple’s:
- When a component is always visible but is secondary to the main content.
- When a component has navigation purposes.
I’ll show you examples for both cases we have in our app at Immoweb.
Custom tabs
In some places, we use custom tabs on top of the screen. It acts as a secondary navigation (the main one being the bottom tab bar). We mimick the behavior of the native tab bar since it is the same type of component.
Search bar/button inside navigation bar
In the homepage and search page, we display a search bar (which is actually just a button which opens the filters screen) inside a navigation bar. So we need to recreate the “Large Content Viewer” behavior of the navigation bar to display its content in large when an accessibility Dynamic Type Size is selected.
Navigation bar “extension”
Another example is the navigation bar “extension” that provides secondary information/actions to the search screen. Making it bigger according to the Dynamic Type Size would take the space needed for the list of results. And since it’s “glued” to the navigation bar, it makes sense to follow the behavior of the navigation bar, keeping it small.
How can we implement the Large Content Viewer?
UILargeContentViewerItem protocol
Since iOS 13, Apple introduced a new protocol: UILargeContentViewerItem
. And every UIView
implements this protocol. It has 5 properties. The 3 first ones speak for themselves:
showsLargeContentViewer, largeContentTitle and largeContentImage
The last 2 properties are:
scalesLargeContentImage: Bool
: whether the image should be scaled to a larger size appropriate for the Large Content Viewer. Iffalse
, it will show the image at its intrinsic size.largeContentImageInsets: UIEdgeInsets
: appropriate insets for positioning the image in the Large Content Viewer so that it appears visually centered.
By default, views like UILabel
and UIButton
will have a largeContentTitle
and a largeContentImage
based on their existing text and image properties.
UILargeContentViewerInteraction
So in order to display a Large Content Viewer for a certain view, you need to:
- set its
showsLargeContentViewer
totrue
- and add
UILargeContentViewerInteraction
to itself or one of its ancestor.
You can do it easily by writing:
myView.showsLargeContentViewer = true
myView.addInteraction(UILargeContentViewerInteraction())
Note:
If you have a group of components you should add the interaction to the view grouping those components.In the example of the tab bar we saw above: it’s the tab bar itself that has the
UILargeContentViewerInteraction
and each tabs that sets theirshowsLargeContentViewer
totrue
.Doing that allows the user to slide his finger from one tab to the next and see the Large Content Viewer updates with the info of the tab currently underneath his finger. This behavior is not available if it’s the same view who implements
showsLargeContentViewer
and the interaction.
When the user lifts his finger up while a Large Content Viewer was displayed, Apple triggers a touchUpInside
event on the active item. So UIButton
’s will be automatically triggered. But for custom components, we’ll need to implement a delegate:
myView.addInteraction(UILargeContentViewerInteraction(delegate: self))
UILargeContentViewerInteractionDelegate
The custom tabs at the top of a page are actually cells inside a collection view. So the default touchUpInside
trigger via the Large Content Viewer will do nothing here. We can overcome this issue by using the UILargeContentViewerInteractionDelegate
like so:
Here we are:
- Adding the
UILargeContentViewerInteraction
interaction to the collection view - Setting the
TopTabBarController
as the delegate of the interaction - Setting each cell to show the large content viewer and setting their titles
- Implementing
UILargeContentViewerInteractionDelegate
to trigger the existing functioncollectionView(_, didSelectItemAt:)
And now we have our custom tabs with the correct behavior 🙌
I am no expert but I’m happy to help you in case you need some help 🙃
Feel free to reach out to me via Twitter!
Special thanks to SeLoger mobile team to have pointed out to me this accessibility feature that we were not yet using in our app.
I hope you liked the article.
See you soon for more adventures 👋
Resources
- This article is heavily inspired on this great article: iOS 13 Large Content Viewer 🔎
- Large Content Viewer — Ensuring Readability for Everyone — WWDC video
- UILargeContentViewerItem — Apple Developer Documentation
Other articles of the “Dynamic Type” series
Special thanks to Mohamed Louli and Vincent Martin for proofreading this article 🙏