Transcript
[ Applause ]
>> Hello everyone, and welcome
to Building Apps with Dynamic
Type.
My name is Clare, and together
with my colleague Nandini, I'm
excited to share with you how
you can make your apps work
great at any text size.
Today we'll first cover what
Dynamic Type is and why the
feature exists.
Next we'll look at what's new in
iOS 11 for Dynamic Type.
We'll follow that with some
guidelines and API you can apply
to your own apps, and finally
we'll show all of that hands-on
in a sample app.
So first what is Dynamic Type.
Dynamic Type is a feature that
allows users to customize the
size of text on screen.
For example, some users may
prefer a smaller text size so
they can fit more content on
screen.
Others may prefer a larger text
size because it's more
comfortable to read.
But Dynamic Type goes beyond a
user's preferences.
Some users may experience eye
strain when viewing text at the
default size for long periods of
time.
Others may simply have less
acute vision due to aging.
And yet others may have a low
vision condition which makes it
impossible for them to read text
at the default size.
So for these users Dynamic Type
isn't just a preference, it's an
actual need and by supporting
Dynamic Type in your apps, you
can allow these users to use
your app and have a great
experience with it.
The Dynamic Type settings can be
found in the Settings app under
Display and Brightness.
It starts out with seven
different text sizes you can
choose from, and the default one
is in the middle.
You can also go into your
Accessibility settings and there
you can enable five even larger
sizes.
Those sizes are geared towards
users with low vision.
They range from somewhat larger
than default size to much
larger.
Now, looking at this you might
be wondering whether you really
need text to get that big.
Let's look in the example of why
this is useful.
So here's the phone app and on
the left we've got it at the
largest size, not including the
Accessibility sizes.
On the right we have it at the
larger size overall.
Now let's look at this through
the lens of a user with low
vision.
Someone with low vision might
see something closer to what we
see here.
Notice how the version on the
left is completely unreadable,
but the version on the right is
still fairly readable, even
though its blurry.
So text size makes a huge
difference for the legibility of
your apps and that's why it's
really important that you
support the full range of
Dynamic Type sizes.
So that's what Dynamic Type is,
and now let's look at what's new
in iOS 11 for Dynamic Type.
The biggest thing that's changed
is that Dynamic Type support is
vastly improved and expanded
across all of iOS.
When we started working on iOS
11, we had three goals in mind.
First, text should be large
enough for the user to read.
In other words, text should
scale with Dynamic Type.
Second, the text should be fully
readable.
It shouldn't be truncated
unnecessarily and it shouldn't
be overlapped or clipping.
And third, we want an app UI to
look beautiful at all text
sizes.
Now, for more information on the
design thinking behind the iOS
11 Dynamic Type improvements,
please check out the Design for
Everyone talk from yesterday.
So now let's look at some
examples of what's changed.
Here's the Settings app.
Notice how it now adapts
beautifully for all the text
sizes.
Here's another example from
Calendar.
Notice how text everywhere is
scaling with Dynamic Type, and
some texts, like the event time,
is laid out differently to
accommodate larger text.
Now, there are some cases where
we don't scale for Dynamic Type.
For example, in tab bars, if we
were to scale a text here, the
tab bar would take away too much
room from the main content.
However, now, in iOS 11, if you
have one of the five largest
Dynamic Type settings chosen,
you can long press on one of the
items in the tab bar.
For example, the Voicemail tab,
and that will show a larger
version in the middle of the
screen.
So that's a sampling of what's
changed in iOS 11.
Now let's look at some
guidelines in API that you can
apply to your own apps.
We'll be covering this in four
areas.
First, we'll look at how you can
scale your font sizes for
Dynamic Type.
Second, we'll see how you can
accommodate larger text in your
app's layouts.
Third, we'll look at the
specific, very common case of
table views.
And then finally, we'll even see
how images can work well with
Dynamic Type.
So first, let's scale font sizes
for Dynamic Type.
The easiest way to do this is to
use the built-in text styles
that come with iOS.
Here's a list of all of our text
styles, along with their font
sizes at the default text size.
If your user has a different
text size selected, these font
sizes will also change.
Now, for those of you who have
already be using text styles in
your app, first, thank you; and
second, there's one important
change in iOS 11 that you should
be aware of.
Prior to iOS 11 all the text
style adapted for the seven
standard sizes.
However, only the body style
adapted for the five
accessibility sizes.
In iOS 11 all of the text style
adapt for all 12 text sizes.
And so if you're using text
styles, you'll get support for
all 12 sizes for free.
To use text styles in Interface
Builder, go to the Attribute
Inspector and change the font on
your view.
By default this will be
something like System 17 point,
which means it's not going to
scale with Dynamic Type.
But if you click on that T icon,
you can choose one of the text
style fonts instead and those
will scale.
Also, new in iOS 11 you can
check the Automatically Adjust
Font checkbox.
This means that if the user
changes their text size while
your app is running, your view
will automatically update its
font for the new text size.
So we highly recommend you check
this on all of your views.
In code it's just as easy to use
text styles.
You can use the
preferredFont(forTextStyle) API
to get a font for the text
style, and then you can use the
adjustsFontForContentSize
Category property to make sure
that your views update their
fonts if the text size changes.
But what if you can't use text
styles?
Maybe you have a design that
requires custom fonts.
The great news is that in iOS 11
it's really easy to get those
fonts to work well with Dynamic
Type.
So let's say you have some code
that assigns the font property
of a label to a custom font of
your choosing.
In iOS 11 you can now use the
new UIFontMetrics class to scale
that font so that it will get
smaller or bigger, depending on
the user's text size.
[ Applause ]
Thanks.
[ Applause ]
In this example we're using the
default font metrics, which
means we're using the font
metrics of the body text style.
That means that if body text
would be 50 percent larger for a
particular user, your font will
also get 50 percent larger.
For better results, you can pick
a particular text style that you
want to scale your font with.
So, for example, if you have a
font that you're using for title
text in your app, you might
choose to scale it in the same
way that we've scaled title1
text.
Now, a final word on web views.
Many of you may have web views
that you're displaying in your
iOS app.
You should make those adapt for
Dynamic Type as well.
To do so, you can use the
-apple-system-body font and that
will get you the body text style
font and it will adapt for the
user's dynamic typesetting.
Now, note that this is only
available on Apple devices, so
if you're planning to use the
same web page for other
platforms, make sure you set an
appropriate fallback font.
Then for your other styles you
can define their font sizes in
terms of relative units, and
that way they'll scale
proportionately.
So that's how you can scale your
font sizes for Dynamic Type.
Now let's look at how you can
accommodate larger text in your
app layouts.
So let's say we've got some text
at the default text size, and
you can imagine that the white
border is the available area on
the screen.
So first step, let's scale the
font size.
We have a problem.
The text is now running off
screen and so your users are not
going to see anything outside of
the white box.
To prevent the label from
running off screen, we can add a
trailing constraint.
But now we still have a problem
because the text is getting
truncated.
The end result is that your
users aren't going to see all
the text.
To really fix this let's wrap
the text and that will allow the
text to grow as much as it needs
while still displaying all of
the text.
To wrap text in Interface
Builder you can use the
Attribute Inspector and adjust
the Lines property on your
label.
By default this is set to one
line, but if you change it to 0,
that will allow your label to
wrap to as many lines as it
needs for its content.
You can do the same thing in
code by setting the number of
lines property to 0.
Okay. Let's look at another
common scenario that can occur.
So when you're writing your app
and you're thinking about the
default text size, it's tempting
to use constant values for your
spacings.
So you might have something like
two labels here whose baselines
are separated by a constant 40
points.
Looks great at the default text
size, but once you start
adapting for Dynamic Type, you
can run into problems like this,
where the labels overlap.
What we really want here is a
spacing that's dynamic and that
accounts for the fonts involved.
In iOS 11 you can now do this
with new Auto Layout System
Spacing Constraints.
You can define the spacing
between two baselines and Auto
Layout will automatically figure
out the best spacing to use
based on the fonts of your
viewers.
Now, if you try this and you
decide that you want a slightly
larger or smaller spacing, you
can do that, too, by adjusting
the Multiplier property and that
will let you get the exact
results you want.
It's also possible to use these
new Auto Layout Constraints in
Interface Builder, and for more
information on that, please
check out the Auto Layout
Techniques and Interface Builder
talk that happened this morning.
Now, I know there are probably
some of you out there who have a
view in your app that was
written eight or nine years ago
and it's just not using Auto
Layout.
Don't worry, we have you
covered.
So let's say you have some
layout code that sets a constant
value and ads that to a y
origin.
Using the same UIFontMetrics
class we saw earlier we can
scale that 40 point value, or
any CGFloat value, and that way
it will get smaller or larger,
depending on the user's text
size.
Now let's look at one final
common scenario.
Here we've got two labels that
are side-by-side at the default
text size.
Again, you can imagine that the
yellow border is the area
available on screen.
Now let's scale our font sizes.
As you can see, there's not
enough room for the text
anymore, so going back to what
we saw earlier, we could try to
wrap the text --
and we'll get something like
this.
So I'd like to step back for a
second and revisit those three
goals we mentioned at the
beginning of the talk.
First, all text should be large
enough to read.
We've got that covered.
Second, all text should be fully
readable.
That's true here.
None of the text is missing.
Third, app UI should look
beautiful at all text sizes.
And that's where we haven't
quite met our goals yet.
As you can see, on the righthand
side the d is being orphaned
from the rest of the word and it
just doesn't look right.
So for this scenario we
recommend that for larger font
sizes you change your layout to
use vertical stacking and that
way each label can grow to the
full width of the screen.
Now, this technique works not
just for text, but for anything
that might take room away from
text.
For example, here's the Siri
Help screen and notice how on
the left, at the default text
size, there's an icon that takes
up a horizontal column away from
the text.
So that's why for larger font
sizes we actually move that icon
above the text and allow the
text to grow to the full width
of the screen.
Now, to do an alternate layout
based on the user's text size
you'll need to know how to get
that.
You can do that by accessing the
preferredConstantSizeCategory
property on either your view's
traitCollection or on the
UIApplication object.
The default text size will
return large and the standard
sizes run from extra small to
extra, extra, extra large.
The Accessibility sizes are
prefixed with Accessibility to
avoid adding more extras.
Now, in iOS 11 we've added new
functions that you can use to
ask questions about the user's
text size.
So, for example, you can check
whether the user is using one of
the Accessibility text sizes,
and if so, you can do an
alternate layout like vertical
stacking,
or you can use any threshold you
want.
We now support compares in
operators so you can check
whether the user's text size is
larger than a particular
threshold.
So that covers some general
guidelines for adapting your
layouts for Dynamic Type.
Now let's look at the specific
case of table views.
Earlier we saw how the Settings
app adapts beautifully for all
Dynamic Type sizes.
The good news is that if you're
using a standard table view
styles, you will get this kind
of layout for free.
So your fonts will grow or
shrink, depending on the Dynamic
Type setting, and for larger
fonts the text will wrap so that
all of it is visible.
Also, for standard table views
that have a detail text label,
those will automatically lay out
with vertical stacking for
larger fonts.
So standard table views will
adapt their layout for Dynamic
Type, and cell heights are based
on their content.
This is particularly important
at larger font sizes where the
text wraps because a cell that
has more text may need to be
taller than a cell that has
less.
So how do we accomplish variable
cell heights in a table view?
We can do this through a
technique called self-sizing.
When self-sizing is enabled, the
table view will ask each cell to
provide its own size and the
cell can calculate that based on
its own content.
Then the table view client
simply needs to give the table
view an estimate for any cells
that are off screen.
In iOS 11 self-sizing is enabled
by default.
However, if you're using fixed
row heights or if you are using
Interface Builder, you may need
to enable self-sizing.
To do so set your row height of
a table view to be Automatic
Dimension and then set the
Estimated Row Height to a
reasonable estimate given your
table view.
If you have section headers and
footers, you can do the same
thing for those using very
similarly named properties.
So that's the story for standard
table view cells.
Now, if you're using custom
cells with Auto Layout, it's
really easy to get these to work
with self-sizing.
All you need to do is set up
your constraints so that they
define the size of the cell and
then Auto Layout will figure out
the size for you.
So let's look at how we could
set up the constraints for this
custom cell shown here, where we
have two labels, one on top of
the other.
We'll definitely want leading
and trailing constraints for
those labels.
And we want to make sure that
the labels are separated
vertically by an appropriate
amount of space.
Again, you can use the new
System Spacing Constraints to
get a value that will work well
at all text sizes.
So are we done?
Not quite.
We still need to add constraints
relative to the top and bottom
of the cell and that will
complete the set of constraints
we need to define the size of
the cell.
Again, you can use the System
Spacing Constraints here to get
values that will look good
across all text sizes.
Now, if you're using Manual
Layout with your cells, you can
also use self-sizing.
To do so you'll want to override
the sizeThatFits method on your
cell, and then you can use the
contentView's width to figure
out the width available for your
subviews.
Now let's move on to our last
topic, images.
Why are images showing up in a
talk about Dynamic Type?
After all, they're not text.
But images are an integral part
of your app's UI and in some
cases they carry meaning that's
not communicated elsewhere.
So for the same reason it's
important for your text to be
readable by your users, it's
also important that your images
are distinguishable.
Let's look at an example.
So here's the Recents view in
the phone app.
Notice how in front of some of
the calls there's an image of a
phone with an arrow pointing out
of it.
This image means that this call
was made by you versus a call
that came in.
Now let's turn up the text size.
For those of you who are
wondering, the image has moved
over here and notice how it is
tiny compared to the text.
If you need your text to be this
big so you can read it, you
probably can't see that image.
So what we really want to do
here is scale the image the same
way that we scale a text, and
that's exactly what we've done
in iOS 11, and better yet, we
made it easy for you to do so in
your own apps.
So to just allow your images to
scale for Dynamic Type you'll
first want to make sure that
your images are provided as
PDF's at 1x scale.
So this is a good idea anyways
because it allows you to use the
same image for both 2x and 3x
resolution devices.
In fact, your app might already
be doing this.
So just make sure you have a
PDF.
Next, go to the Asset Catalog
and check this new checkbox for
Preserving Vector Data.
If you don't check the checkbox,
when the Asset Catalog is
compiled, it's going to
rasterize all the PDF's.
But if you check the checkbox,
the original PDF gets preserved,
and the cool thing about that is
that now if you use this image
and put it into an image view of
any size, the image will get
drawn smoothly using PDF
Drawing.
[ Applause ]
Now, the final step is to make
sure that your view resizes for
Dynamic Type.
To do this in Interface Builder
you can select any image view or
button and you can check the new
Adjusts Image Size property.
This means that your image
viewer button will scale up for
the five largest Dynamic Type
sizes.
And you can do the same thing in
code with the Adjusts Image Size
for
AccessibilityContentSizeCategory
property.
There's one more place where
image scaling comes in handy,
and that's when the user long
presses on a bar item.
So earlier we saw how you can
long press on the Voicemail tab
to show a larger version in the
middle of the screen.
Notice that both the text is
scaling and also the image.
So we want to make sure that
that image looks as good as
possible.
If your bar item is using a PDF
image, all you need to do is
check the Preserve Vector Data
checkbox that we saw earlier.
That will allow UIKit to scale
it up smoothly.
If you're not using a PDF,
you'll want to provide a larger
version that we can show when
the user long presses on that
image.
To do that in Interface Builder
you can go to the Attributes
Inspector and set the
Accessibility property of your
bar item to be the larger
version.
Or in code you can simply set
the largeContentSizeImage
property to that larger version.
So we've just covered a variety
of tips and tricks you can use
to adapt your apps for Dynamic
Type.
And now I'd like to invite
Nandini to the stage to show all
of that in a sample app.
[ Applause ]
>> Hi everyone.
I'm Nandini.
I'm a software engineer in the
Accessibility Team at Apple.
Today, using a sample app, I'll
show you how you can fix your
app in very little time with
[inaudible] font sizes.
First, I will open the app in
the default text size, and later
I'll open the app in the largest
of the Dynamic Type font size
and fix issues along the way.
Let's start the app.
We cleared it.
It's called Cute Battle Pets.
In this app you can choose among
two pets to battle with each
other.
Let me open the app now.
In this tab, Opponents, you see
a list of pets you can choose to
battle among each other, and the
next tab, Achievements, you see
a list of badges of honors these
pets can earn.
Before auditing our app for the
largest of the Dynamic Type font
size, if we switch back to the
Opponents tab, you can audit
your app for the largest of the
Dynamic Font size using a very
handy tool in Xcode called
Accessibility Inspector.
This tool is very handy because
you can audit your app before
going to the Settings app on
your device.
You can open this tool by going
to Xcode in the menu bar, choose
Open Developer Tool and then
click on Accessibility
Inspector.
This tool can be used to audit
apps in all macOS and iOS
iPhones, including the
Simulators.
As our app is running on the
iPhone Simulator, I'll choose
Start from the dropdown menu.
I'll go to the Settings tab in
the Accessibility Inspector.
Here you see a font size slider.
The font size is currently the
default text size.
I'm going to move the slider's
knob to the last notch on the
slider.
That is the largest of the
Dynamic Type font size.
Let's go back to our app now to
see the effect of this change.
The font size of these labels
has not changed yet.
Any idea why this is happening?
This is happening because of two
reasons.
The labels here are not yet set
to automatically adjust to the
user's ContentSizeCategory, and
the petName and petDescription
labels here are using custom
fonts.
Let's go to a project now to fix
these issues.
I'll minimize Accessibility
Inspector for now.
I'll go to BattleCell zip file.
Here, using the jump bar, I'll
move to Set Up Labels and
Buttons Method.
Here for petName, petDescription
and battleButton's titleLabel,
I'll set the property at this
font for ContentSizeCategory and
I'll set it to True.
As petName and petDescription
are using custom fonts, we can
use UIFont, make it API, scan
font for font metric.
For petName I'll be using the
headline TextStyle.
For petDescription I'll be using
the sub headline TextStyle.
Let's run the app again and see
the effect of these changes.
Now, after these labels are
adjusted to the user's
ContentSizeCategory, we see that
these labels have really less
horizontal room to grow.
With the menu on the left and
the button on the right, these
labels have really less
horizontal room to grow and the
labels either truncate or wrap
in multiple lines.
We can fix this by having an
alternate adopt layout for
larger text constraints.
We can achieve this by moving
the image above the text and the
button below the text.
This will ensure that the labels
are less of wrap and truncated.
Let's go fix this in our project
now.
First, before adding this
adoptLayoutConstraints for
larger text constraints, let me
add a private variable for that.
Next let me go to
setupLayoutConstraints method.
Here you see that you already
have a set of layout constraints
for default text size.
Now I'll be placing a set of
constraints for larger Dynamic
Type font sizes.
These set of constraints pasted
here will be available in the
sample app code attached along
the session website.
You can go and review this after
the session, but I give a short
overview of what this actually
do.
These constraints ensure that
the image labels and the button
are vertically stacked, and
these constraints also get them
in the height of the cell.
Okay. Let's go to our
developerLayoutConstraints
method.
Here we see that one of the
developer constraints aren't
activated.
We need the larger [inaudible],
right.
Let's fix that.
Here, based on user's
preferredContentSizeCategory,
they put in the five largest
Dynamic Type font sizes.
With the app you will be able to
look at its constraints and
activateLargeTextConstraints.
Otherwise, do the reverse
operation.
To ensure that these layout
constraints are up-to-date based
on the change in trait
collection, we call this method
if trait collection did change.
If the user's
preferredContentSizeCategory
shifts from the five largest
Dynamic Type font sizes to the
smaller Dynamic Type font sizes,
or visa-versa, these layout
constraints will be updated.
Let's run the app again to see
the effect of these changes.
Great. After vertically stacking
the content the labels are less
of wrapped and there's no
truncation at all.
Let's go the next step,
Achievements.
When we run the app in the
default text size, you will
notice that these cells here
have multiple lines of text, but
currently only one line of text
is visible on screen.
Let's go to Achievements View
Controller in Swift check on why
this is happening.
This is happening because the
table view's row height is set
to a constant value, hundred.
This makes that these cells do
not have cell size at all.
To fix this and make this cells
have size we have to set the
table view's row height to use
UITableViewAutomaticDimension,
and TableView's
estimatedRowHeight to a constant
value, and I'll choose hundred.
Let's run the app again.
Let me go to Achievements tab.
Now we see that we have more
lines of text in each of these
cells, and the cells, they're
sized to fit content, but let's
take a look at the [inaudible].
Unlike the labels the images do
not grow, according to the
user's ContentSizeCategory.
To fix this let's go to
Achievements [inaudible] file.
And set the label and image view
method.
For the badgeImageView I set the
property adjustsImageSize for
accessibilityContentSize
Category, and I set it to two.
This will ensure that the image
is scaled for the five largest
Dynamic Type font sizes.
Let's run the app again to see
the effect of this change.
Let me move to Achievements tab.
Great. Both the labels and the
image have sizes largest Dynamic
Type font size, but let's take a
closer look at the image in
these cells.
Let's also take a look at the
large text only that comes up in
a long press on the tab bar
icons.
Based on that, the images in
these cells and also in the tab
bar icons were not smooth.
To fix that we have to go to
Assets Catalog, choose our
images, those are PDF images, go
to the Attributes Inspector and
click on the Preserve Vector
Data checkbox.
If we do this, what happens is
the PDF vector data is preserved
and the images are rendered
smooth in different Dynamic Type
font sizes.
Let's run the app again to see
the effect of this change.
Let me go to Achievements tab.
For confirmation, let me zoom in
again.
Now we see that the images here
are rendered smooth, right.
Finally, using the Accessibility
Inspector, I'm going to run
through a quick audit of this
app and different Dynamic Type
font sizes.
For that let me minimize Xcode.
Let me bring up the
Accessibility Inspector.
Let me move the first tab,
Opponents.
Let me switch the font size
slider to default text size.
Now I'm going to increase the
font size one-by-one and you'll
notice that the labels in these
cells increase according to the
user's ContentSizeCategory.
When I move to the five larger
Dynamic Type font sizes, the
layout of these cells change.
The labels have more horizontal
room to grow and the cell says
sizeToFitContent.
Next move on to Achievements to
do the same audit.
I'll switch back to default text
size.
I'll increase the font size
one-by-one.
Now, you see that the labels
wrap in multiple lines.
The cell says sizeToFitContent,
and also the image scales in the
five larger Dynamic Type font
sizes.
So there you have it.
Our app looks pretty great in
all the Dynamic Type font sizes.
So using the new API's available
in iOS 11, you can make your
apps, too, work for all Dynamic
Type font sizes.
Now I welcome Clare back on
stage to conclude the
presentation.
Thank you.
[ Applause ]
>> Thanks, Nandini.
So all of that sample code is
available on our session
website, but the version we have
on the session website is
actually expanded to include
even more examples.
So you can see how we do this in
Interface Builder.
You can see an example where we
wrap text around images.
You can find a case where we
allow scrolling only when
necessary for larger fonts, and
more.
Think of it as a recipe book for
things you might encounter in
your own apps.
So we highly encourage you to
check it out after the session.
To summarize what we covered
today, it's easy to support
Dynamic Type with new API in iOS
11.
If you have an app that doesn't
support Dynamic Type, now is a
great time to do so, and you
should because supporting
Dynamic Type is good for your
users.
It's good for the users who
prefer smaller text because it
allows them to see more on
screen.
It's good for the users who
prefer larger text because it's
more comfortable to read, and
it's especially beneficial for
users who need larger text in
order to be able to read it.
When more apps are usable by
people with a disability, such
as low vision, it really helps
to level the playing field for
those users.
And so by supporting Dynamic
Type in your app, you're
actually making the world a
better place.
So we really hope you take what
you saw today in today's session
and go back and make apps that
work well with Dynamic Type and
include more users so that more
users can benefit from the great
work you've done.
For more information, including
the sample code we showed,
please go to our session
website.
Now, there have been several
sessions at this conference
related to the one we just gave.
As we mentioned earlier, the
Design for Everyone talk from
yesterday covers the design
thinking behind the iOS 11
Dynamic Type improvements.
There are also two sessions on
accessibility, What's New in
Accessibility and Media and
Gaming Accessibility.
Both of these sessions cover how
you can widen your user base and
include more users.
And finally, as we mentioned
earlier, to learn more about the
System Spacing Constraints in
Interface Builder, check out the
Auto Layout Techniques in
Interface Builder talk.
Thank you all for coming, and I
hope you enjoy the rest of the
conference.
[ Applause ]