Transcript
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Silence ]
>> Hi. I'm Ian Baird, iOS
Text Kit Lead Engineer.
And today, I would
like to talk to you
about what I personally think
is one of the coolest features
in iOS 7, and I know
you're going to want
to use it in your app.
I want to introduce
you to Text Kit.
First, let's lay out an
agenda for today's talk.
We're going to talk a little
bit about the motivation,
why we created Text Kit.
Next, we're going to talk
about what is Text Kit,
how it's composed, and
why you should care.
And then we're going to give
you a quick tour of some
of the headline features
in Text Kit,
and I think you're
going to be impressed.
And finally, we're going to wrap
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
up with an awesome demo
showing you how to use
and display Rich Text inside
of your app in noble ways
that you can only
do using iOS 7.
So let's get started.
Motivation.
Why did we do Text Kit?
Well, quite simply, we
needed it to realize the type
of graphically heavy and complex
designs that you see in iOS 7.
In the beginning,
we had NSString --
sorry, we had String
Drawing and we had WebKit
which were both based on
Core Text and Core Graphics.
And upon the stack, we were
able to build almost all
of the UIText components.
And this worked really
well for many people.
And like yourself, I was
a third-party developer
and I made great
apps using the stack.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But occasionally,
it wasn't enough.
You'd have to drop down to
Core Text to turn on kerning
or to have ligated glyphs.
And as we all know, Core
Text is very advanced.
I read your tweets.
I saw what you guys said.
As a matter of fact,
somebody even called it a rite
of passage.
And this complexity is really
just inherent in the system
because Core Text is an
advanced Unicode layout engine.
You use it to build
a complex text system
or a web toolkit on top of it.
It's really overkill to use it
to render a label especially
when all you want to
do is kern your text.
So that being said, the
great thing about Text Kit
and Text Kit's design is that if
you've invested the time to come
up to speed on Core Text,
this time is not lost.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The way the system is layered,
most concepts are Toll-Free
Bridged to Text Kit.
You can use a CTFont for a
UIFont, a UIFont descriptor
for a CTFont descriptor.
It's that easy.
[ Applause ]
You know what, if you
couldn't use Core Text,
a lot of you would embed
rich web content inside
of your application.
And this is great.
UIWebView is awesome for
embedding web content.
And the reason it's awesome is
because it's built on WebKit
and WebKit is the preeminent
HTML rendering system
for the mobile platform.
It's awesome, it kicks ass.
Unfortunately, there
are a couple of places
where you can't really use
it, like in ScrollViews.
And this had unfortunate
consequences
for UIText components
that were built on top
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of WebViews like TextView.
It made it really hard
to use them in places
like collection view or
table view cells or anything
which required animations.
So we were faced with all
these challenges and we looked
around the company to
see what we could do.
How could we expose
the power or Core Text
without exposing our developers
to the necessary complexity
of an advanced Unicode
layout engine?
And I think you're going
to love our answer to this.
Our answer to this
problem is Text Kit.
So what is Text Kit?
Well, if you are going
to take away one point
from my talk today, I'd like you
to know that Text Kit is a fast,
modern text layout
and rendering engine.
It's built on top of Core Text.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And so this is awesome.
It gives you all the power
and flexibility of Core Text
without exposing you
to the hairy API.
A hairy API which uses CF types
which as we know are
not necessarily --
aren't friendly or developer --
or easy for developers to use.
And even better,
it features great,
and I mean great
integration with UIKit.
What does this do for you?
Well, it gives you
everything that you want
because it's built --
everything, all of the
UIText components are built
on top of Text Kit.
[ Applause ]
And as I was saying
a moment ago,
this gives you complete control
over all of the text rendering
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in your UIText elements.
UITextField, UITextView,
and UILabel were completely
rebuilt on top of Text Kit.
And so this gives you seamless
integration with animations,
UICollectionView,
and UITableView.
You won't get white
flashes anymore.
Things scroll onto screen.
It also features an extensible
object-oriented architecture
with support for customization
features like subclassing,
delegation, and even has rich
support for notifications.
If you're already using UIKit
and other Cocoa frameworks,
you know how to use Text Kit.
You know how to bend
it to your will.
So, that's Text Kit.
The next thing I want to tell
you about today is I want
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to give you a high-level
overview of some
of the headline features
inside of Text Kit
and how I think you can
use them in your app.
And the first thing I'd like
to start out with is something
that was difficult to do
in years past using text
components we gave you.
Now, using Text Kit, it's easy
to create paginated layouts.
It's easy to lay
out text in columns.
Text wrapping around
arbitrary figures
and shapes, that's simple too.
And again, as I said, you
even have superior control
over Rich Text editing inside
of your app, and this allows you
to have access to features
like interactive text coloring.
As the user types into your
app, you can change attributes.
Let's pretend I'm building
an interactive client
for a popular internet
messaging service.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Just pretend, this
is hypothetical.
I type in my friend's handle,
and it just sort of sits there
in the content, just
blending in.
And you know what I'd like
to do, I'd like to view this
with meaning, I'd like to make
a pop out to user by coloring it
and making it stand out from
the rest of the content.
This is now easy to do with Text
Kit, just a few lines of code.
Text folding is also
easy to accomplish
with just a few lines
of code in Text Kit.
And next, this is one of the
features I think you're going
to think is the coolest,
custom truncation.
Well, the great thing about the
iPhone and one of the reasons
that we love it is that
it fits in your pocket.
The downside of that is the
screen is incredibly small,
even on the new iPhone 5.
And sometimes, especially
when you're using some
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of the new text styles,
not all of the content
that your user has
selected or you want to show
to the user will actually
fit on that display.
So in the past, you were
stuck with tail truncation,
head truncation, or
middle truncation.
Using Text Kit and
a few lines of code,
you can have custom
truncation now.
Also enhanced in iOS 7, all
of these techniques work
in standard controls, you
don't have to subclass TextView
to have custom truncation
or text folding.
Isn't that cool?
[ Applause ]
And building on our
heritage from iOS 6,
in the attributed text support
that we've brought to you
in iOS 6, we have now extended
UITextView and UITextField
to support all text attributes.
[ Applause ]
And as Toby and Jason
and everyone else
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with Toby this week,
we've extended kerning
and ligature support everywhere
and we've turned
it on by default.
And we've even given you
simple single attribute access
to advanced text
effects like Letterpress.
If you want to know more
about this, I would suggest
that you see the session
Advanced Text Layouts
and Effects with Text Kit.
So, the next thing I'm going to
tell you about is another thing
that I think is just
incredibly awesome in Text Kit.
And Jason and Toby
and everyone else
and Chris have been
talking about this all week.
It's Dynamic Type.
What's Dynamic Type?
Well, Dynamic Type is a
set of designed type styles
which are made for you
to use in your app.
They're optimized for
legibility, so they're easy
for your users to read.
And again, it's user-centric.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Your user is able
to pick the size.
They can go small,
medium, or large.
And there's rich support
for accessibility built
right in to Dynamic Type.
And there's great support
for Dynamic Type in Xcode 5.
So, to really utilize Dynamic
Type to its fullest potential,
you're going to want to know
about the next feature
I'm about to show you.
Font descriptors.
Now, for those of you
coming from Core Text,
this is not necessarily
all that new.
But for the rest of us
who have been using iOS 6
and previous versions,
it's really, really cool.
Font descriptors are a way of
specifying one or more fonts,
and you can interact
with the font system
by using a font descriptor
for query --
to query for a font and it will
return the results in the form
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of more font descriptors which
then you can hand to the system
and tell it, "Hey, create a
font for this font descriptor."
This is a big improvement
over the past.
In the past, you have to create
a font, change the point size,
apply a trait, a symbolic
trait of some variety,
and everytime you
were doing this,
the system was creating a font
to back this UIFont
instance in the background.
You don't have to do that
with font descriptors.
They're super cheap
and lightweight.
They can be archived.
And if you want to know more
about using fonts with Text Kit,
I urge you to see the session
Using Fonts with Text Kit.
It's going to be really awesome.
So you have these fonts and
they're working well for you.
But, maybe you get a design that
says, "The new fonts are great
but we just need bold here."
How are you going to do that?
Well, you're going to do
that with symbolic traits.
You can see here we have our
regular unadorned type styles,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
a nice list of them.
Let's apply bold and italic
attributes, and you can see --
or sorry, symbolic traits
and you can see what
it does to those fonts.
We also have support for the
expanded and condensed traits.
And if you want to
affect the line spacing,
we even have traits for that.
For example, the
tight trait allows you
to pack more text
into a smaller area.
Now, when you do this,
and I wouldn't recommend
that you do it all the time,
but you can do it in places
like summary fields where
information density is
at a premium for your user,
and you don't want sacrificing
a little bit of legibility.
So you wouldn't want to
do this all over your app.
And if you're embedding rich
web content inside your app,
I've got great news for you.
All of this is supported
by WebKit.
And if you want to know more
about the great enhancements
to fonts in WebKit, you should
see the session What's New
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in Safari and WebKit
for developers.
Next, I'd like to show you how
we built one of the components
in the UIText world,
the TextView.
Here's our simple TextView and
it has a nursery rhyme in it.
Well, how was it built now?
In the past, it had a
WebView backing everything.
The first thing you're
going to see
when you pull it apart is
the NSTextContainer instance.
NSTextContainer is giving the
NSLayoutManager the bounds,
the geometry to render
the text into.
And NSLayoutManager is
taking all of the text
from your NSTextStorage
and turning it into lines
of glyphs inside
of your TextView.
But now that you understand
how TextView is built,
this unlocks other
features for you.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Like, again, when
we were talking
about exclusion paths before,
the way you do this inside
of a TextView, the way you
get support for simple figures
and cutouts in your
UITextView is
to first create an
exclusion path.
In this case, we're creating an
exclusion path for a butterfly.
And then you would take
this exclusion path,
you'd pack into an array, and
you'd set it on the text --
the exclusion path's
property of the text container
which is associated
with your TextView.
And that's all you'd have to do.
At that point, the text
just magically wraps
around your figure.
It's that simple.
[ Applause ]
Thank you.
It's an easy and
declarative model.
You'll notice, there
was no subclassing
or delegation involved.
So let's talk a bit more
about text container.
What is a text container?
A text container defines a
coordinate system and geometry
for an NSLayoutManager.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
As we talked about,
exclusion paths live entirely
in the NSTextContainer's
coordinate space.
Hit-testing is also done
in the NSTextContainer's
coordinate space,
and I'm teasing another big
feature that we've enabled
for you in TextViews in iOS 7.
Hit-testing.
In the past, whenever
we laid out text --
[ Applause ]
I'm glad you like it.
In the past, when
we laid out text,
we immediately threw away
all of the information,
all of the extents, the glyph
IDs, everything just went away
and we gave you back a bit map.
Now, NSLayoutManager
keeps all of this around.
And this is useful
for you because now,
if you want to resolve a tap to
a character index, all you have
to do is call this API.
User's finger comes down.
You get the index into
your text storage, and bam,
you have your character.
It's that simple.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In order to understand the next
few features, we have to go
over some front matter
about glyphs.
What is a glyph?
A glyph represents
one or more characters
on the screen or
the printed page.
An important thing to
remember about glyphs is
that there's not necessarily a
one-to-one mapping from a glyph
to a set of characters
or vice-versa.
Now, you may wonder, "How
do I do this mapping then?"
Well, the answer is our
friend again, NSLayoutManager.
NSLayoutManager maintains
this mapping of glyph ranges
to character ranges and
it's really easy to use.
Just call this API, pass in the
glyph range and it will map,
in the case, the
FFI ligated glyph
to the three characters
it's representing
and it can go the other way.
It's that easy.
And it will maintain this
mapping through edits,
programmatic manipulations,
attribute changes,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
whatever you do, NSLayoutManager
always stays up-to-date.
There are a whole host
of new interaction
features in TextView.
Now, in the past, you may say,
"Well, you can always interact
with links," and
that's absolutely true.
But what it necessitated was
it necessitated using data
detectors and putting in a
web style, maybe HTTP link.
What's new in iOS 7, and what
I think you're going to love,
is that you can turn
any arbitrary text range
into a link now using
NSLink attribute.
[ Applause ]
Associate a URL with
it, and now,
you have a rich interaction
model right out of the box
that your users are
going to love.
We still support data
detectors, they're there.
You see, we have the
Moscone Center address.
The user taps or long-presses,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and up comes an action sheet
filled with useful interactions
for the user to choose from.
Now, in order to understand the
next feature, I want to tell you
about text attachments.
The text attachments have
been a long time coming
to our platform, but they're
really cool and really useful.
And they're totally distinct
from exclusion paths,
and I'm going to tell you why.
Attachments live with your data.
They actually live inside
of your NSTextStorage.
There's a character
which is interpreted
and has the attachment
data associated with it.
They can refer to an
image or something else.
An exclusion path lives
inside of the text container.
It actually changes the geometry
that the layout manager
uses to flow text into.
That's the difference.
So what do you generally
use a text attachment for?
A text attachment is usually
used for inline images.
It affects text layout and
it's affected by text layout.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And, of course, it
contains the geometry
for the contained data
including a baseline offset.
NSLayoutManager is going
to use this information
to place the text attachment in
line with the rest of your data.
And, of course, it has another
simple interaction model.
The user long-presses
on the picture,
and up comes another
action sheet.
Again, this is built
right into the system.
To show you some of the
stuff and how you can use it
in your app, I'm going to invite
my colleague Jordan Breeding
to the stage to give
you guys a quick demo.
[ Applause ]
>> Thank you, Ian.
The first part of the demo we'd
like to show you today is the
show for our demo application.
As you can see, I already have
it running in the simulator.
What I'd like to call out is
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that this collection view is
backed by collection view cells.
They contain UILabels
and UITextViews.
That's right.
It's a full-blown UITextViews
in collection view cells.
They scroll well.
There's no synchronization
issues.
I didn't have to deal
with any main thread
and web thread synchronization.
To show you that I didn't
actually do anything tricky,
I'm going to open my storyboard,
go into my cell, and now,
I'm showing you that inside
of my background container,
I have a UILabel and a
UITextView, and I'd also
like to call out a specific
feature that Ian pointed out.
New in Xcode 5, into
interface builder,
you can directly select the
text style that you would
like instead of the
old system choices.
In this case, I had selected
the text style of body
because this represents some
body text inside of our cells.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now if I build and run again --
I can enter our first
section of the real demo.
This is the basic
interaction demo.
What we're showing you here
is that we have some blocks
of texts which do not
match any data detectors.
And if you go in right
now, you'll notice
that neither the phone
number nor the URL is
actually interactive.
We'd like to make
it interactive.
So we go back into Xcode,
into interface builder.
We select the view that
contains that data.
And just like in iOS 6, it's
as easy as turning on the links
and phone numbers data
detectors which I've just done.
Now, if I build and run,
building and running now,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
going into basic interaction.
You'll notice that phone
numbers and URLs work perfectly.
Now, something that you
might have had to do
in the past is customize that
behavior that you just saw.
You might not want your
users to go to Safari
when they tap on
a particular link.
In the past, to achieve
this, many times,
you had to layout your
content in a UIWebView
and use the interaction
model with their delegates
to then force it to open
in your application.
I'd like to show you that
today, we've given you just
that directly in
UITextViews in iOS 7.
Going to go into the
view controller for this.
And what I'd like to
show you is right here,
I implement the delegate.
I've set myself
as the TextView's
delegate in my storyboard.
And as you can see here,
I just implement TextView should
interact with URL in range.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In this case, I compare the
host of the URL to www.apple.com
and if that's what it is,
then I open my own
WebViewController instead
of Safari.
Building and running
to show you that now.
And now, when you're user
goes to the apple URL,
you'll see that it opens
a WebViewController.
Your user stays in
your application,
doesn't leave your experience.
[ Applause ]
We thought you might like that.
Next, our designer gave us a
spec for an exclusion path demo.
Our designers specified
some body text upfront
and gave us a butterfly
image to put
on the bottom right-hand corner.
They also specified that we
should have a pan gesture
recognizer so that the user
could move the butterfly around.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The issue that you
have upfront is
that when the user moves
the butterfly, the butterfly
and its drop shadow affect
the text and overlay it.
We'd like to show you how
easy it is to fix that issue
in iOS 7 with UITextViews.
I'm going to go into my
exclusion path view controller.
First thing I'm going
to do is drop
in a method that
I wrote upfront.
This grabs my precalculated
Bezier Path for my butterfly.
In this case, I can
precalculate it
because the image never
changes, just its position.
I pull my plist out of my
bundle, then I need to make sure
that my image rect
for my butterfly is
in the correct coordinate space.
And finally, I transform
my Bezier Path to match
where the butterfly currently
is on screen and return
that Bezier Path here.
In viewDidLload, I'll use
the new one line support
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in UITextView to set the
exclusion paths then I'll handle
the case of layout
occurring again.
Whenever layout occurs, we know
that the butterfly could
have moved and we need
to match the Bezier
Path to the butterfly.
So, I dropped in
some code there,
do a viewDidLayout
subviews method and go ahead
and update the exclusion
paths there as well
on our UITextView's
text container.
Lastly, in our pan gesture
recognizer action method,
we know that the butterfly
has also moved in this case.
So again, we drop
in the one liner
to update the exclusion paths.
Now, I'll build and run.
And now, in the exclusion paths,
you can see how fluidly --
[ Applause ]
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You can see how fluidly
that butterfly moved
throughout the text
and let everything
flow back around it.
So, what did you
see in that demo?
You saw that we still
support data detectors
for basic interaction in
TextViews but you also saw
that now you can
provide a delegate
and you can customize some
of your user's behavior
when they interact
with that information.
You saw brand new in iOS 7
that TextViews can be used
in collection view cells and
everything worked perfectly.
You saw how to use some
of the new text styles
in interface builder
and in Xcode.
You can also use them in code.
And lastly, you saw our one
line support for exclusion paths
so that you can make
great looking interfaces
for your users.
Next, I'd like to turn it back
over to my colleague, Ian Baird.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Applause ]
>> That was a great demo.
So now that you're faced
with all of this coolness,
the reality is probably
starting to sink
in that there might be some
work involved in realizing some
of these new designs that your
designers and your clients
and maybe even your friends
and families start throwing
at you once they see iOS 7.
So now we're going to tell
you a little bit about some
of the techniques you can
employ to realize some
of these designs
you're going to see.
So that you can work on creating
apps like messages and mail.
If you look at the design
of messages and mail,
you can see that the text
is precisely positioned.
Everything looks
balanced and clean.
And the content is
front and center.
Well, I'm going to tell you, you
want to get as far down the road
as you can with Auto
Layout because it's going
to make your life
incredibly easy.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But, once you get past what
Auto Layout can do for you,
you're going to need
to understand a few
more tips and tricks.
Let's start with an example.
The new mail view is
broken up into sections.
You can see there are a
couple of header sections
and then there's a body section.
Each section is separated
by a gray key line,
and this key line is
important, it's very important
to get our text spaced
exactly in the perfect place
with respect to the
positioning of the key line.
And our designer has driven
this home by saying that we need
to put the first line
of the body text 0.8
times the cap height away
from the key line.
You may ask, "What is this?"
To understand some
of these new designs,
you need to understand a few
things about font metrics.
So again, if you have a detailed
spec like the one we showed you
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in Mail, you'll need
to become familiarized
with things like line height.
This encompasses the
ascender and descender
of each glyph on the line.
As a matter of fact, it's
called the typographic balance
in this case of the line.
And you can get this
from the font
by asking for its line height.
The next thing you're
going to want
to understand is cap height.
Cap height is the distance
from the bottom of the baseline
to the top -- the capital letter
in this case like the flat line
of the A or the -- if
you have a capital H,
it's basically the two top
parts, and that was the distance
that our designers specified
that we should position
our text relative to.
Next, you're going to want
to understand leading.
Leading is the space
between the lines of text,
and using Dynamic Type, remember
that this leading can be
negative to drive the lines
of text closer together.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This causes the descenders
from the line above to overlap
with the ascenders
from the line below.
Now, all of these designs
need to be responsive
and the user gets
to derive the size.
How do you do this?
We're going to want to listen
for UIContentSizeCategoryDid
ChangeNotification.
Thankfully, we have
auto complete,
and this will be omitted when
the users selects new size.
You want to setup this
observation probably inside
of your view controller,
and maybe your app,
and probably your
view controller.
And you want to re-layout
your UI when you receive this.
Well, if you're using Auto
Layout, again, as we told you,
you should probably do,
you'll need to invalidate
the intrinsic content size
of your UIKitViews
positioned by Auto Layout.
And this is a mouthful and
it really boils down to,
if it's a UITextView, or a
text field, or a UILabel,
simply resetting the font
on that view will invalidate
the intrinsic content size
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and Auto Layout will just
layout everything for you.
It's that simple.
However, if you're doing
pixel perfect positioning
like the stuff I was
talking about earlier,
you'll want to call
setNeedsLayout
on probably a parent view
to reposition all the child
views using whatever magic
formula you and your
designer have come up with
to position these views.
Another key thing to
remember is that you need
to invalidate any
cached preferred fonts
or font descriptors because
these guys are no longer valid
in the context of your
user's new chosen font size.
So, there's a lot there but
it's actually pretty simple.
It shouldn't be too
intimidating.
And to show you just
how easy it is,
I'd like to invite my
colleague Jordan Breeding
up to the stage again to
give you another demo.
[ Applause ]
>> Thank you, Ian.
The next thing we'd like to show
you in this demo is how to deal
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with some of these complex
designs and also how to account
for your user changing their
preferred content size.
Now, the first thing I'd like
to show you is a user changing
their preferred content size.
In this case, you can see what
our current collection view
looks like.
And as the user goes
over to settings
and changes their
preferred content size --
-- going back to our
demo, you'll notice
that nothing happened.
Now, that's a very
inconsistent user experience.
Your users expect
their content to change
when they change
the content size.
So in this case, I'm going to go
to my collection
view cells instead
of the collection
view controller
because the cells
themselves know
about which content
needs to change.
First thing I'm going to
do is declare a method
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that our notification
can call when it happens.
In this case, I'm calling it
PreferredContentSizeChanged.
Next, while I'm setting up
our initial layout and state,
I'll actually listen
for that notification
that Ian mentioned earlier.
UIContentCategory -- sorry.
UIContentSizeCategoryDid
ChangeNotification.
When that notification fires,
it will call our
PreferredContentSizeChanged
method.
Lastly, I'll drop
in an implementation
of PreferredContentSizeChanged.
In this case, I wrote
a method upfront
that just grabs the new fonts,
places them on the views.
Everything is happy.
So I'll build and run.
Now, you'll see that
things are laid
out a little bit differently.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And again, when your users goes
to change their text size --
oh, actually, I think I --
yeah, I did build instead
of a build and run.
Now we'll see that the
content is different.
And as we go back down,
everything lays out
automatically.
In this case --
[ Applause ]
In this case, another thing we'd
like to point out is that each
of these UITextViews was
actually positioned inside
of the cell using Auto Layout.
So all we did was set the
font on the UITextView
and it automatically invalidated
the intrinsic content size
and caused layout to happen.
The next thing we'd like to show
you is a design specification
from a designer.
In this case, our designer
wanted a profile picture
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in the upper left
as you can see.
A name, some text, and then
a large run of text below it.
I'd like to show you
how we actually achieved
that using Auto Layout.
In Xcode 5, we were able
to select the picture
which was the most
important element.
Our designer had told us
that the element needed
to be exactly eight
points from the key line
and from the left-hand margin.
And if I show you here, you can
see some of these constraints.
Then the label flows from that,
it's eight points
from the image view.
And then some of the rest of
the layout flows from there.
This container is positioned
based on the left-hand side
of the label above it
and the right-hand side
of the label above it.
And the final TextView is eight
points from the things above it,
and it's left and right
margins are aligned
with the items above it.
The reason that we did this is
that you can adjust just a
few things at the top and all
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of the rest of your layout
will flow from there.
So, if we build and run again
just to show you, all right.
And in this case, I
could show you that --
if I go in and set the
preferred content size,
it's not currently responding.
So we need to make that happen.
What I do there is I go into
my view controller superclass
and I implement the same
PreferredContentSizeChanged
method.
In viewDidLoad, I know
that I need to listen
for the notification again
and call
PreferredContentSizeChanged,
and have a base implementation
of that.
Lastly, in the view controller
for our designed part,
we know that we need
to override that method
and do some extra setting
of fonts and things.
So, I build and run.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And now you'll see that if I go
in and change my content size,
everything lays out
automatically.
[ Applause ]
Thank you.
The one thing that you might
notice is that the short block
of description text
truncated in a way
that wasn't very
pleasing to our user.
We didn't like this and
neither did our designer.
So we're going to implement one
last thing, brand new in iOS 7.
We can now set the line break
mode on the text container
of the TextView to
get truncation
by the text container instead
of by the line or paragraph.
So instead of truncating
to a single line
or even a single paragraph,
I've inserted this
single line of code.
I'll build and run.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And this time, you'll notice
that we truncated nicely
at the end of the
text container itself.
So, going back over to
what we saw in that demo,
we saw how you can realize
fairly complex designs still
using Auto Layout in Xcode
5 with interface builder.
We saw how you can respond
to the change notification
when your user changes
their preferred content size
and cause layout to occur again.
And we saw how in iOS 7, you
can now customize the text
containers line break
mode instead of having
to do it yourself by
line or paragraph.
Next, I'd like to bring out my
colleague, Johannes Fortmann.
[ Applause ]
>> Thanks, Jordan.
Hi, I'm here to talk to you
about Interactive Rich Text.
Now, what do I mean by that?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If you've used the UITextView
on iOS 6 before, you may recall
that there, we provided
the new attribute
to set the attributed
text on a UITextView.
Now, this attribute means that
when you set it, the entire text
in this UITextView
will get replaced
by the new NSAttributedString
that you set the attributes to.
In iOS 7, we now provide a
new attribute, text storage,
that allows you to directly
modify the attributed text
on the TextView.
The text storage is a subclass
of NSMutableAttributedString
which means that you can
get it from the TextView
and modify it in place.
We send change notifications
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that will inform the
LayoutManager about the changes
that you performed
on the text storage
and performed very specific
invalidation on only the parts
of the text storage
that you've changed.
That's a big, big, big
performance win, since now,
we don't have to
invalidate everything
when just a single
character has changed.
Let's walk through how one
of these changes works.
As I said, since the
NSTextStorage is simply a
MutableAttributedString
subclass,
we can use the standard
modifications
on the MutableAttributedString
to perform changes.
So, assume that we have
a TextView already here,
and in this case, we have the
beginning of the story "Alice
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and Wonderland" and we want
to modify the name Alice
for example to be read,
to call it out in a way.
What we do since we
have multiple occasions
by the name Alice comes up, it's
about her, the story, anyway.
So, it happens often.
We don't want to perform
an invalidation for each
of these cases why we
modify the text storage.
So what we do is we
bracket the changes.
Let me show you how that works.
First, we call the Begin Editing
method on the text storage.
That informs our text
storage that we're going
to perform a batch
of changes now.
Next, what we're doing is
we modify each instance.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
For example, we loop over the
string, find out the ranges,
and set the foreground color on
each instance of the word Alice.
And finally, once we're
done with all our changes
and are happy with them, we
call the End Editing method
on the text storage.
Now, until now, nothing
has yet changed
on the actual visual
representation, the TextView.
Only after the End Editing
method has been called,
the text storage will
process each and every edit
and inform the LayoutManager
which then is able
to recompute the areas
that have actually changed
and redraw the actual changes.
Next, I'd like to talk to you
about subclassing NSTextStorage.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, why would we
want to do that?
Well, as Ian showed you before,
we might be writing an app
for a popular messaging
system, and in that case,
we want to call out a
person by their identifier.
We do know that these
identifiers have a
certain formatting.
So, in that case,
we already know what
to do once we see
these identifiers.
After the user has
entered the identifier,
we want to immediately,
and I mean,
immediately change the truth,
effectively the contents
of our text storage
to for example change the
colors of this identifier.
To do that, we modify the
methods on the text storage
that actually change
text on the text storage.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, NSTextStorage
is class cluster.
That means that we as Apple
provide an implementation
of a superclass, that's
the NSTextStorage class
that is public in the SDK.
And we also provide
an implementation
of that superclass, a
subclass, that is private
but that's still vended
out to you, the developer,
if you initialize
one of these objects.
This subclass provides
the actual storage
and attribute modification
parts of the text storage.
Now, if you as a
third-party developer want
to provide your own
custom implementation
of a text storage, what you need
to do is provide
certain primitive methods
on the text storage.
There are four primitive
methods.
Two of them deal with
actual static storage.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You can inquire the string
and inquire about attributes,
and the next two deal
with actual modifications.
To show you how to
actually implement this,
I'm going to do a demo.
I've already setup in the
same demo app here a TextView
that has the text we saw in
the slides and already entered.
I've also already created
an empty implementation
for custom text storage.
We're now going to try to use
this empty implementation.
Well, we're going to fill it
before we use it of course.
First, I need to actually make
on my view controller an outlet
for the custom text
storage and, of course,
I need to create an instance
of my implementation.
Now, I'm going to do something
slightly complicated here.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In Ian's -- in one
of Ian's slides,
you've seen that the TextView
is backed by a text container
which in turn is backed
by a LayoutManager
which in turn his
backed by a text storage.
That means that I have to
recreate this entire hierarchy
to be able to put my custom
text storage in there.
This is really quite
simple since we're not going
to do anything custom
with these LayoutManagers
or text containers.
So I'm just going to create
a stock LayoutManager.
I'm going to also create stock
text container within the size
of our TextView in
an infinite height.
I'm going to setup
the text container
such that its width
tracks that TextView
in case we resize the TextView.
And finally, I'm going
to hook these two app.
I'm going to add the text
container to the LayoutManager
and add the LayoutManager
to the text storage.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Finally, instead of creating
a simple TextView here,
I'm going to use the new in
iOS 7, designated initializer
for your TextView that takes
it to custom text container.
So, I'm creating the TextView
with this specific text
container that I just made,
and I assign and add it.
If I were to run this now,
we would have a TextView
that is backed by text storage
that does not actually
store anything
because we have not implemented
any of the primitive methods.
So let's do that.
I'm switching over to the text
storage implementation here.
And what we want to --
what we need first is an
NSMutableAttributedString
that actually stores the data.
We need something to store
attributes and strings.
So I'm creating an instance
variable for my backing store.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In my initializer, I create
a new MutableAttributedString
for that backing
store, and that's it.
Next, I'm going to implement
the static methods string,
it just returns the backing
store string, and attributes
at index returns
the back attributes
at the specific index.
The mutable methods
look similar.
They just fall back
to the backing store,
but there is something
different here.
We also need to inform
our superclass,
the NSTextStorage class, that
we actually did some edits.
So I'm going to do that
calling the Edit method on --
or myself to inform my
superclass about the range
that has been changed.
Now, next, I want to -- if
I've changed characters,
I want to remember that
and perform modifications
on those characters.
So implement a flag to
remember if I changed something.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In my replace characters and
range method, I set that flag
and then I'm going to implement
the process editing method
that gets called when the final
end editing call has been sent
to the text storage.
I'm going to call super in
there, and if the flag is set,
I'm going to perform
certain replacements.
These replacements are simple.
I'm going to find
the range of the line
that has just been edited and
I'm going to apply some tokens
to those -- to this range
depending on the words in there.
These tokens are
just dictionary of --
dictionaries in fact that
apply attributes to the string.
Finally, in my view
controller, I set the tokens.
I'm going to choose
the word Alice
to get the program color
red and the word rabbit
to get the program color orange.
Let's run this.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And now, if I type,
you can already see
without me typing the
word Alice is red,
the word rabbit is
orange, and if I type,
as soon as I'm finished typing,
the word turns red immediately,
same for rabbit of course.
What you've seen
in this demo is how
to assemble the text
system by hand.
We've assembled the
stock classes
and inserted custom
text storage.
We subclass the NSTextStorage
to perform certain --
well, first of all, to
actually work, and then finally,
to use the subclass
of the text storage,
specifically the process
editing method element
to perform interactive
modifications
on the content while
the user is editing it.
And with that, let's
wrap this up.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Text Kit is an extremely
powerful
and new feature of iOS 7.
UITextViews as well
as UITextFields
and labels are first
class citizens of UIKit.
They are usable in table
views and collection views.
They support all the
attributes that previously
in iOS 6 NSString supported,
plus a few more like links.
Using exclusion paths and
simple overrides on --
in this case for the exclusion
path, the text container,
but also on NSLayoutManager
or text storage,
we are able to provide very
pleasing UI for our users.
And finally, we've
seen how customizable
and extensible it is.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We were able to, in just
a few lines of code,
provide an implementation
for one of the classes here
and leverage that
to perform something
that was not possible
frankly in iOS 6 before
at least not in a
performance way.
With that, if you
have any questions,
we have our frameworks
evangelist,
Jake Behrens around here.
I think he's sitting down there.
He's -- yeah.
We've got extensive
documentation already out,
I believe.
And finally, all of us text guys
are regularly reading the forums
and are happy to
answer questions.
We've got three more sessions.
Well, one of them
is already over
but the Advanced Text Layout
session tomorrow where Aki
and Peter will show you how
to override certain things
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
on NSLayoutManager
and use delegation
to customize your text
layouts even further.
And on Friday, we've
got a session
on Using Fonts with Text Kit.
We've got awesome new Core
Text features providing
for interesting modifications
on fonts.
And the last one on Tuesday,
we had a session about the --
among other things, the
new CSS Style Values.
Thank you.
[ Applause ]
[ Silence ]