Transcript
[ Music ]
>> Hello. My name is Sommer
Panage and I'm an engineering
manager on the Accessibility
team here at Apple.
I'll be talking about the Large
Content Viewer.
A feature that helps people who
prefer larger text sizes.
In this talk, you'll learn how
to ensure that all parts of your
app are readable for everyone.
We'll first cover what the Large
Content Viewer is and why it's
important.
Next, we'll look at some API
that will allow you to support
it in your app.
Finally, we'll cover examples of
some situations you might
encounter in your app and how to
handle them.
So let's start with some
background.
Before we talk about the Large
Content Viewer, let's review a
related topic, Dynamic Type.
Dynamic Type is a feature that
allows you to customize the size
of text for the system.
You can make it smaller if you
want to fit more content on
screen, or you can make it
larger and more readable.
By default, you can choose
between seven different sizes.
But if you go into your
Accessibility settings, you can
enable larger sizes and then you
get five additional sizes.
This is important because many
people aren't just using this
feature because they prefer a
different text size.
They're doing it because they
need a larger text size in order
to be able to read the text.
So let's take a look at how
Dynamic Type changes the
behavior of iOS.
Here's how the phone app looks
at the default text size.
Now, if I change my text size to
one of the Accessibility sizes,
the text gets much bigger.
However, you might have noticed
that part of the text on screen
is not getting bigger.
For example, look at the button
in the bottom left.
If the customer has set their
size to be large like we see in
the content area, then they
likely wouldn't see the text
that we see in the tab bar
because it's still small.
You might not be able to make up
the icon above it either in
fact.
However, we don't want to grow
the tab bar because that would
leave very little room for the
main content that you see, in
this case your contact list.
So instead, if you're using
larger text sizes, we allow you
to long press on that button to
see a larger version.
Here's how that looks.
You can now drag your finger
along the bottom bar to see
what's on each of those buttons.
When you finally drag your
finger onto the button that you
want to tap, you can just let go
and the Apple act as though you
tapped the button.
This feature is what we call the
Large Content Viewer.
It allows people with low vision
to use tab bars or any other UI
that has to stay small.
It's important for your app to
show the Large Content Viewer
when appropriate.
If you're using standard UIKit
bars, you already showed the
Large Content Viewer.
You might just not have noticed
it before because it's only
enabled for the Accessibility
text sizes.
But if you've got a custom bar
or some other custom UI that has
to stay small, you'll need to
implement some API so that your
UI works just as well as the
standard UIKit controls.
Remember, this is only for the
case when your custom UI cannot
grow in size.
Scaling with dynamic type is
always preferred to showing the
Large Content Viewer.
But sometimes, our bars simply
can't scale.
So let's look at how you can
support the Large Content Viewer
in your app.
Earlier, I said that you already
showed the Large Content Viewer
if you're using standard UIKit
bars.
But you might still need to do
something to make sure that it
looks good.
If your bar items use PDF
images, make sure that you check
the Preserve Vector checkbox in
the asset catalog as seen here.
That will ensure that your
images scale smoothly to larger
sizes.
If your image button doesn't
have vector data, for example if
you're using a PNG, then by
default that image will look
blurry when it's shown in the
viewer.
To fix that, you'll need to
provide a larger version of the
image.
Use the large content size image
property on UI bar item to do
that.
If you need to adjust the
positioning, for example, if
your image doesn't look centered
in the viewer the way you wanted
to, then you can adjust the
large content size image in
sets.
So what do you need to do if you
have custom UI?
Well, before iOS 13, you
basically had to make your own
Large Content Viewer from
scratch.
But now, we've added API that
allows you to show the same UI
that's shown for standard UIKit
bars.
So let's say you have a custom
tab bar, first you'll need to
specify the buttons in your tab
bar as items to be shown in the
viewer.
Then the Large Content Viewer
needs a title and/or an image
for each of those buttons.
If you happened to be using
standard UIKit classes for those
buttons, you'll get those for
free.
Finally, you'll need to set up a
gesture interaction on the
custom tab bar itself.
The new UILargeContentViewerItem
protocol specifies the info that
the Large Content Viewer needs
in order to show your content.
This showsLargeContentViewer
property is what you'll use to
mark your tab bar buttons.
Set it to true on any views that
should present the viewer.
Then you can specify a
largeContentTitle and a
largeContentImage.
You can specify either of those
or both of them.
If you want to reuse a PDF image
from a small button, you can set
the scalesLargeContentImage
property to true.
But just as we saw earlier with
UI bar item, make sure that you
preserve the vector data for
your image.
And lastly, if you want to
center your image, you can use
the largeContentImageInsets.
UIView already implements this
protocol and it also provides
setters.
So in many cases, you can just
set the properties rather than
having to subclass and override.
Also, as we mentioned earlier,
certain UIKit classes like UI
button and UI label, return
default values for their title
and image.
So that's how you annotate the
buttons in your tab bar.
Next, you'll need to add a
gesture interaction to the tab
bar itself.
To add the interaction, you'll
use the same addInteraction
method that's used for adding,
drag and drop support.
Here's how the interaction for
the Large Content Viewer works.
It's got a few properties on it.
In the simple case, you can
create an instance of this
interaction with no arguments
and you don't need to touch any
of the other properties here.
But if your app has other
gesture recognizers, you may
need to customize the behavior.
You can provide a delegate to
get fine-grained control over
how it works.
You can also use the
gestureRecognizer property if
you need to set up relationships
with your app's other gesture
recognizers.
Finally, to find out whether the
Large Content Viewer is enabled,
you can check the isEnabled
property.
And of course, you can listen
for the notification to see when
that changes.
There are a few ways to
customize the behavior using the
delegate.
First, you can specify what
happens when the user lifts
their finger from an item in
your custom view.
It should act as though the user
tapped on that item.
If you don't implement this
method and you're using a
standard UI control like UI
button, by default it will get
sent a touchup inside event.
But if you got something more
custom there, for example a view
with its own tap gesture
recognizer, you can implement
this method to provide the
behavior you need.
Next, there's an option to
provide the item at a particular
point.
By default, the item will be
found by calling point inside
with event recursively on your
view hierarchy.
But that might not work if you
aren't using views for example.
So, this method lets you return
which item should be shown in
the viewer for a particular
point.
Finally, you can decide which
viewController should house the
Large Content Viewer.
By default, UIKit will try to
pick a viewController that
contains the view that you added
the interaction to.
But if that default choice
doesn't work well for your app,
you can specify one here.
So, we've covered the API.
Now let's look at some examples
showing how to use it.
First, let's look at a simple
case.
You've got a custom bar but
inside you've got standard UIKit
views.
Here we've got a bar with a UI
button and a UI label.
Because we're using standard
views, all we need to do is up
to the button and the label in
using the
showsLargeContentViewer
property.
There's no need to specify a
title or an image since those
can be inferred from the views
of the properties.
Finally, we can add the gesture
interaction to the custom bar
with no need to modify any
properties.
That's it.
If your custom bar uses
something else for its buttons,
then you'll need some of the
other API.
Let's say each of your buttons
is an instance of a MyButton
custom class.
You can override the UI Large
Content Viewer item properties
on your buttons to return the
right info.
Here we're returning true for
showsLargeContentViewer and
we're returning our text as the
title.
If you have an image with vector
data for each button, then you
can use the exact same image for
the Large Content Viewer.
Just make sure to return true
for scalesLargeContentImage so
that it grows to the correct
size.
Finally, let's look at an
example when you need to deal
with another gesture recognizer.
A classic example from one of
Apple's apps is in Safari.
When you tap on the Back button,
it goes to the previous page.
But when you long press on it,
it brings you to page with your
past browsing history.
The Large Content Viewer also
uses a long press gesture.
So how do you get those to work
together?
You should absolutely allow both
things to work.
In other words, let the Large
Content Viewer show so that
people can see what's on the
button.
But once they've had a chance to
read it, do the thing you would
normally do on long press.
To do that, first, let's
increase our existing
longPressRecognizer's duration.
That way we'll give people some
extra time to show the viewer
first before we do the other
action.
You should also make sure you
update the duration if people's
setting change.
If they start or stop using one
of the Accessibility text sizes,
the duration should also update.
Next, let's set a
UIGestureRecognizer delegate on
the existing
longPressRecognizer.
Now, in your delegate callbacks,
you can make sure that both of
your existing
longPressRecognizer and the
gestureRecognizer from the Large
Content Viewer can recognize at
the same time.
That way, neither one of them
will prevent the other from
working.
Here, we can see the behavior
with our Large Content Viewer
implementation.
If I lift my finger while the
Large Content Viewer is visible,
I go back as expected.
However, if I long press for the
longer duration, I can still get
to that browsing history.
So that's how your app can
accommodate people who prefer
larger text sizes even for UI
that needs to stay small.
Note that you should only use
the Large Content Viewer for UI
that can't scale.
Scaling for Dynamic Type is
always the preferred option.
So if you can do that, don't use
this as API.
Finally, if your custom view has
other interactions, make sure
that those are all still
possible for people who use the
Large Content Viewer.
That way, everyone can use all
of your app's great features.
That's it for now.
Thanks for watching.