WWDC2017 Session 211

Transcript

>> Good morning
[ Applause ]
.
Thank you.
I'm Chris Dreessen.
This is Touch Bar Fundamentals.
If you have no idea whatsoever
what Touch Bar is, I'm not sure
how you got here, but I'm glad
you're here.
Likely most of us are a bit more
familiar with Touch Bar, but we
may not have had a chance to
actually play with it.
So, let me orient you to it.
So, we have here a picture of a
MacBook Pro and in place of the
F keys you might be used to, we
have this thing we call Touch
Bar.
And this is an interactive input
and display device.
And let me familiarize you with
these parts.
On the left, we have the escape
key, which should be pretty
familiar to everyone.
And on the right, we have this
thing called the control script.
And you can go ahead and
disclose the control strip if
you want.
And you'll have basically the
old media functions the F keys
offer.
And you can use this the same
way you always have, button
presses.
You don't have to disclose it
thought.
You can actually just go ahead
and use it in its collapsed
form.
And when it's its collapsed form
it has some neat functions too.
We can just do like a glancing
swipe over the volume button and
adjust the volume directly.
So, there's a lot of
conveniences here for adjusting
certain system functions.
But, that's not really the most
interesting parts of Touch Bar,
the most interesting parts are
between the escape key and the
control strip.
And that's where your
application content is going to
go.
And so, let me show you what
some of our system applications
have done with this.
So, here we have photos.
And this is just browsing the
photos library.
And we can actually go ahead and
scrub through our photo library
here.
It's just like in iOS with
direct input with our finger, so
we plop our finger down on the
Touch Bar and it's just tracking
it.
We also have momentum swipes
there if we want to browse
through it quickly.
If you go to edit a photo, this
is the photos crop and rotate
tool.
And they have this rotation
thing in the middle of the Touch
Bar and it tracks your finger
directly, which is pretty fun,
because it's sort of like
actually rotating a picture on a
table.
Finally, photos also exposes
filters.
So, we can scrub and swipe
through our filters here.
And this is an interesting use
of Touch Bar, because normally
if we were using a mouse or a
track pad, we'd go ahead and
look at our photo and then look
at the filters section and move
the mouse or track pad to that,
select the next filter.
And with Touch Bar we can
actually keep our eyes on the
cat.
Here's QuickTime Player.
QuickTime Player has a scrubber
control directly in the touch
bar, so we can move a movie back
and forth, it's pretty neat.
And they've also gone ahead and
exposed a similar control for
trimming, so we can adjust the
beginning and end of a movie
that we've recorded.
Something I'd like to point out
about QuickTime Player here, is
that QuickTime Player didn't
write any code to do this, this
is all inside of AVKit and
AVPlayer view.
So, if you're already using
AVKit, you've probably got this
functionality for free,
congratulations.
Let's look at text edit for a
moment.
So, everyone's familiar with
QuickType on iOS.
And We've gone ahead and brought
QuickType over to Touch Bar on
macOS, and as everyone know
QuickType is a great short
fiction writing tool.
So, if we go ahead and write a
short story here, 'the fact is
he has to;' this is not the best
short fiction I've read.
But that's okay, because Touch
Bar gives us a way of spicing
that up.
We also have the emoji picker.
And, let's go ahead and spice it
up a bit.
We can browse our emoji here and
say I laughed until I cried, I
was turned into a frog, and I'm
happy I'm no longer a frog.
So, we've added some nice human
emotion and drama to our story,
all thanks to Touch Bar.
TextEdit of course, is a text
editing tool also, so we can
collapse the QuickType options
here and bring up text
formatting controls.
And maybe the most useful thing
is to make it bold, or italic,
or add some color to it and pink
feels right for the story where
I'm turned into a frog, and not
a frog again.
Anyway, let's never speak of
that.
Something else I want to point
out about all these examples
I've show you is that they're
customizable.
We have a customization panel
for Touch Bar.
And you can rearrange items in
it.
You can add items from the
customization panel on the
screen or remove them from the
Touch Bar.
And this is important, because
every user's workflow is a
little bit different.
Some are doing different things
with your application, and
others just prefer to use the
computer in a different way.
And by enabling customization,
you can give users the exact
experience they want.
And I'll teach you how to do
that programmatically in just a
little bit.
Let's cover some of the
technical details and some of
the implications that come with
that.
So, the Touch Bar is the
beautiful P3 retina display.
It has a nice P3 color gamut,
great blacks, wonderful
contrast.
And that means that our assets
we include in our applications
don't have to cover as much as
what we do on the main screen.
Additionally, it's a true multi
touch device, which means we can
actually track multiple fingers.
And that affords us some new
options for what sort of
controls we might make.
You're going to hear this a lot
about Touch Bar, that it's
context sensitive.
And that's very neat in terms of
enabling the user to work with
functions in the application
that are appropriate, but it has
implications for event handling,
because the context in the
application might change, which
the user is using the Touch Bar,
and our controls need to react
to that.
And finally, we actually go
ahead and take some care to
match the key taps and glyphs on
the Touch Bar to those on the
physical keyboard, and we do
that by watching the ambient
brightness, and knowing whether
or not the keyboard backlight is
on.
But this has implications for
how we might draw custom
controls.
And we're not going to go into
detail on any of those
implications in this session,
but we do have a session later
this afternoon that will cover
all these topics.
So, I'm assuming that once
you're done here, maybe even
before that, you're going to be
really jazzed to add Touch Bar
support to your application if
you haven't already.
But when you're coming up with
your UI's there's a few things
to keep in mind.
And the first of them, the prime
directive of Touch Bar is that
the Touch Bar is an input
device.
It's meant to be interacted with
by the user.
It's not supposed to be
displaying things.
So, no status indicators or
stock tickers.
The next thing we should keep in
mind when making our Touch Bar
UI's is that we don't want to
put functionality in the Touch
Bar that doesn't exist anywhere
else in the application.
It's great to have null and fun
Touch Bar UI's, but it shouldn't
be the only way of accessing
functionality.
And there's a good reason for a
lot of that, and that's that not
every user has a Touch Bar, so
if you only put something in the
Touch Bar, you're going to be
losing out on functionality for
a lot of users.
And finally, this is almost a
side effect of saying the Touch
Bar is an input device.
While we want creative beautiful
UI's in the Touch Bar, they
shouldn't be taking center
stage.
The content the user's working
with on the main screen should
always be their focus.
So, the Touch Bar shouldn't be
distracting.
With that out of the way, we're
going to go ahead and cover the
core classes that let you use
the Touch Bar in your
application.
We're going to cover how the
responder change is integrated
with these for discovering what
context sensitive functionality
to display.
And then, we're going to go
ahead and take a deep dive on
one of those core classes and
show you most of what it can do.
So, let's start with the
classes.
The first class is of course
NSTouchBarItem.
And that plays with NSTouchBar
and NSResponder.
And let's just take a closer
look.
This is a mockup of the mail
Touch Bar I've made.
And everything I'm highlighting
here, is an NS view, or NS
control, or NS button.
They're all things you're very
familiar with because Touch Bar
is reusing the existing view
functionality we've been using
in our Cocoa apps for very long
time.
There's a few things though that
Touch Bar does, that view isn't
prepared to do.
So, we need some way of adapting
that.
And that's what this
NSTouchBarItem class does.
So, it binds a view to the Touch
Bar.
NSTouchBarItem itself is a very
basic class.
It's intended to be sub classed
and that's probably not
something you're actually going
to have to do.
Because AppKit includes about
half a dozen existing Touch Bar
subclasses that will handle a
lot of the needs you're going to
have.
And finally one of the most
important features of the
NSTouchBarItem class is that it
has an identifier that uniquely
identifies that item and
functionality within its
NSTouchBar instance.
So, let's talk about NSTouchBar
itself.
The most important thing is that
it has an array of those item
identifiers that identify the
items.
And this is important for
resolving what functionalities
goes into the Touch Bar to the
views used to display it.
Let's take a quick look at a
code snippet.
So, here we're going to go ahead
and just declare some
identifiers for a shark and sea
turtle.
Usually when you come up with
identifiers for our code, we
recommend using reverse DNS, but
these are a little bit more
legible.
And once we have those
identifiers, we're going to go
ahead and instantiate a new
NSTouchBar and just set the
default the item identifiers
array.
And this let's AppKit know what
sort of semantic functionality
we're putting in the Touch Bar.
What we're going to cover now is
how AppKit resolves that.
And there's two ways we do this
look up.
There's two ways we find
NSTouchBarItem from the item
identifiers.
And the first is a property on
NSTouchBar called template
items.
And this is just a set of items.
So, if we go back to some code
snippets, this is what we had
before, exactly the same, and
we've added some.
So, here I'm using an
NSCustomTouchBar item class for
the shark and turtles
respectively.
And this is one of those
subclasses I mentioned.
And we're just setting the view
of these items to an NS button.
And we go ahead and we make the
title, you know the shark emoji
or the turtle emoji.
You'll notice we're using the NS
button convenience constructor
we introduced in macOS 10.12,
and that's important because
these convenience constructors
will configure the buttons to be
appearance sensitive to use the
right styling and font.
And if we build an NS button
directly, we may not get that
functionality.
So, this is a big time saver.
But, finally after instantiating
these items, we're just going to
go ahead and stuff them in the
template item set.
And if we do all of this, we're
going to wind up with the Touch
Bar we see at the bottom of the
screen, with our shark button
and our turtle button.
Something I'd like to mention,
if you go ahead and copy and
paste the code on the slide into
a Swift playground, XCode will
go ahead and preview the Touch
Bar items we construct and the
Touch Bar itself.
And this is a pretty useful way
of rapidly prototyping your
Touch Bar UIs.
So, that's template items.
Let's go ahead and cover what we
can do with the delegate.
So, there's a single delegate
method in the NSTouchBarDelegate
protocol.
And that's Touch Bar,
makeItemForIdentifier.
And it's pretty simple.
If we take a look at this code
here, this is exactly the same
as the template items case.
What's different is we've
structured it in a switch
statement, so we can go ahead
and conditionally create a new
item when AppKit asks for one of
our specific identifiers.
AppKit cahces the result of this
method.
So, you really can just treat
this as a factory and make a new
instance each time.
You don't have to maintain a
back pointer yourself, unless
that's useful for other reasons.
Something else that's important
to mention is, you know I've
covered customizability a little
bit, and let's take that Touch
Bar we've made and make it
customizable.
So, that involves adding a few
things.
The first bit is actually this
top line, where we go ahead and
tell NS application to set
isAutomaticCustomize
TouchBarMenuItemEnabled.
That's a mouthful, but it's
actually a very simply way of
handling this.
If you set this to true,
NSApplication is going to go
ahead and create a menu item for
you automatically that will show
and hide the customization
panel.
You don't have to use that.
NSApplication has a method to
show and hide it explicitly and
you can wire that up to your
menu item if you want a little
bit more control.
But with that out of the way,
let's look at the bottom of the
code in this slide, where we set
the customization identifier.
And in this case, I'm just
making up an ocean animal
identifier.
But it's important to set this,
because this is the token which
enables persistence of the Touch
Bar configuration across
launches of your application or
reboots of the system.
And there's one other important
step for enabling customization,
and that is to set this
customizationAllowedItem
Identifiers array.
And we're just going ahead and
set it to our shark and sea
turtle again.
But setting this allows the
customization panel to know
which items can be added and
removed.
If we do all of that, we can
bring up the customization panel
and we'll see exactly this, the
defaultItemIdentifiers array is
translated faithfully to the
default set of items on the
left.
And the individual items from
the allowed item identifiers are
shown on the right.
This is kind of a boring
customization panel and we can
spice it up a little.
So, here's a whole menagerie of
ocean animals.
Something I want to mention, and
it will come into play with
deciding whether you're going to
set the template items on a
Touch Bar when you create it, or
whether to use the delegate is
by default we were only showing
the shark and sea turtle.
And there's a lot of
applications where your default
functionality in the Touch Bar
is going to be a very small
subset of the total
functionality you can add
through customization.
By using the delegate, users who
don't bring up the customization
panel aren't going to pay the
CPU time of creating new items.
Something else to mention here
is you may have a situation
where you're building a Touch
Bar UI and there's some
functionality you want to be
there all the time, you don't
want the user to be able to
remove it in customization, and
if you have a case like that you
can set the customization
required item identifiers array.
And in this case, obviously, the
sea turtle is critical for the
function of our application.
So, we're going to prevent it
from being removed.
So, that kind of covers how to
make instances of NSTouchBar and
how to facilitate item lookup by
the item identifier, through the
template items and delegate
methods.
But one of the things we're
missing is how the applicant
finds those instances of
NSTouchBar.
And I big part of that is the
NSTouchBarProvider protocol.
And it's a fairly simple
protocol.
It's just exposing a read-only
Touch Bar property.
NSResponder itself implements
this protocol right out of the
box.
And we'll cover that in just a
second.
But sometimes it's useful to
attach a Touch Bar to your
application delegate, or window
delegate.
And neither of those is likely
to be a subclass of NSResponder.
So, let's see how you go ahead
and implement that protocol
yourself.
This looks like a lot of code,
but really we're just using a
Swift lazy variable here for the
Touch Bar property.
And the first time the Touch Bar
property is accessed, Swift is
going to go ahead and run this
block to instantiate our Touch
Bar.
All the code to create the item
in bar and stuff we looked at in
the previous slides.
Something else to mention is
that AppKit key value observes
this property.
So, if you feel the need to
replace your Touch Bar
wholesale, we'll notice that
sort of change.
Let's look at how NSResponder
implements this.
First, it exposes that Touch Bar
property as a read-write
property instead of read-only.
And the significance of that is
that you can set instances of
NSTouchBar on various pieces of
your application.
On the responders, you have in
your windows.
Like views and view controllers,
and window controllers.
And that's really neat because
you don't necessarily have a
subclass for each and every one
of those controls.
If you are making a subclass of
a control, or really any
NSResponder, NSResponder also
exposes this makeTouchBar
method.
So, makeTouchBar is pretty
simple.
The first time the Touch Bar
property is accessed on an
NSResponder, it's going to call
self makeTouchBar and run this
code.
And we just have to return a new
Touch Bar for it.
A lot of the system controls and
system frameworks, which expose
functionality use this method to
provide it.
So, I mentioned that NSResponder
has a read-write Touch Bar
property and you can set the
touch bar.
And one of the most important
clients of that is actually
Interface Builder.
So, let me show you how to build
a Touch Bar UI from Interface
Builder.
If we go ahead and start with a
new story board, we have a
window controller seen here, and
we can filter the object library
to show us Touch Bar controls.
So, if we just check the object
library, here an instance of NS
Touch Bar and we can drag that
onto our window controller.
And now we have an empty Touch
Bar to play with and going back
to the object library, we can go
ahead and see that there's
dozens and dozens of
preconfigured controls and Touch
Bar items we can just drag into
the Touch Bar.
And from here, we can wire these
items up with ID connections, or
bindings or whatever.
And it's actually very possible
to write Touch Bar apps that are
perfectly functional and useable
without ever writing a line of
code for it.
So, that covers creating
instances of NSTouchBarItem.
Let's see how this fits into the
bigger responder chain and how
we discover all of these
individual Touch Bar instances.
So, a refresher, a responder
chain is made up of instances of
the NSResponder class.
And one of the most important
properties of the NSResponder
class is this next responder
property it has.
And that just points at another
responder.
But it basically means that
given a responder, we've
anchored an entire chain of
responders capable of handling
events and actions and things.
And AppKit uses many different
responders as the anchors for
chains for handling keyboard
events, and actions and kit
testing and routing mouse events
and things, but let's cover how
keyboard event works.
Because Touch Bar is part of the
keyboard.
So, we're going to have an
NSEvent handed to us by the
system, and that's going to go
over the NSApplication.
And NSApplication is going to
say what do I do with this
keyboard event.
And most NSApplications are
going to say do I have a key
window?
Okay, it gets the keyboard event
now.
And the key window meanwhile is
going to have the same question,
what do I do with this keyboard
event.
Every NS Window had a property
called first responder and
that's designating where the
responder chain starts for
keyboard events and actions and
things.
So, the key window is going to
go ahead and say, all right
let's send this event to my
first responder, like in its key
down or key up method.
So, the first responder
meanwhile it's interesting,
because that's where it's
anchoring the responder chain,
where we're going to be handling
this as a responder method, not
just generic event routing.
But it's going to have a
decision, do I handle the event
in key down, or do I call super
and let it pass that to the next
responder.
So, let's say it passes it to
the next responder.
Usually the first responder will
be a view, the second responder
will be a super view.
It will make the same choice.
And these days, use and view
controllers tend to be
[inaudible] in the responder
chain.
So, pass it up to a view
controller, have the same choice
handler call super.
It doesn't handle it.
It might even go and reach all
the way back to the initial
window that routed the event in
the first place.
And that, as part of the
responder chain, can make the
same decisions whether to handle
it or pass it on.
And that can percolate all the
way back up to the application.
So, that's how we handle
keyboard events.
Touch Bar is part of the
keyboard.
So, it also turns out these are
all the places we can attach
instances of NSTouchBar.
And we search them in exactly
the same order the keyboard
event was routed through the
responder chain.
So, one question you should be
asking is hey, I notice you have
five instances of NSTouchBar
here.
How do you go from that to one
Touch Bar on the device.
And I'm going to cover that in
just a second.
But first I want to make a small
note about views and views
controllers.
You're probably going to be
attaching a Touch Bar to a view
controller at some point, making
your application.
And you'll run and test this.
And you're going to see that
your Touch Bar doesn't show up
at all and you'll think, oh, I
guess my view controller is not
in the responder chain.
And you'll go ahead and look at
your view controllers view and
see that its next responder is
indeed your view controller.
And what's going on here is that
while your particular responder
chain is set up correctly, it's
not anchored in the first
responder of the window.
And that's often because the
first responder of the window
has to return true for the
acceptsFirstResponder method.
So, if you wind up in this
situation, it's really easy to
subclass NS View or whatever
your first responder is to
accept first responder and make
a valid responder chain anchored
at the first responder.
So, let's get back to how we're
going to handle multiple
NSTouchBar instances on this.
The easiest thing to remember is
that the responder, with an
NSTouchBar closest to that first
responder, so closest to the
keyboard input, its Touch Bar is
going to win and take over the
whole thing.
Calling back to earlier where I
mentioned that AVKit and some
other system frameworks provide
support, you're probably
thinking that they're likely
going to provide support in NS
Views which are going to be
closer to the first responder
than your window controllers or
application delegates might be.
So, we need some way of sharing
the device Touch Bar across
multiple instances of NSTouchBar
and we have a way of doing that.
And that's accomplished with
this special item identifier,
called the otherItemsProxy.
I say it's a special item
identifier because you don't
have to create any item for
this.
You don't have to put it in your
template item set, you don't
have to handle that identifier
in your delegate and make item
for identifier case.
But when you go ahead and
include other items proxy in
your default item identifier
array, when AppKit is harvesting
NSTouchBar from the responder
chain, it will go ahead and
replace the otherItemsProxy with
the items from responders closer
to the first responder.
So, let's look at that in
action.
Here's an example of mail.
My keyboard focus is on the
recipient's field.
And the recipient's field is
providing suggestions for who I
might to send the email to.
I also have this send button on
the left side of the application
section of the Touch Bar.
If I were to change my keyboard
focus instead to the composition
view in the window, I have a
bunch of text formatting
controls and an emoji picker.
But I still have that send
button.
And the way this breaks down is
that mail's composed window
controller has a Touch Bar with
a send button and an
otherItemsProxy.
And the recipient's field is
providing the candidates.
And the recipient's field is
very close to the first
responder, so it's going to get
first shot at that.
But the window controller
including the otherItemsProxy
means we can merge those two
Touch Bars.
Likewise, for the composition
view, the window controller is
exactly the same instance, it's
just the responder chain
anchored at the first responder
includes the composition view
before the window controller.
Something else to mention is
that this is completely
compatible with customization.
We use the otherItemsProxy to
build the default set of items,
like you'd expect.
And we go ahead and union the
allowed items from the eligible
touch bars.
So, we can see we can customize
the send button in mail, even
though it's provided by a
different responder than the
formatting controls.
You might think, hey the
otherItemsProxy sounds pretty
great for the reliable
functioning of my Touch Bar
stuff, and you'd be right, but
there's a few cases where you do
want to omit it.
And if we go back to mail, but
close all the windows, we're
going to see that we have a new
viewer window button in the
Touch Bar.
And that's provided by the
application, but it omits the
otherItemsProxy.
When we go ahead and bring a
window up that has Touch Bar
content it's going to be closer
to the first responder, and the
lack of the otherItemsProxy in
the farther out Touch Bar means
it gets replaced entirely.
So, there's another sort of
special item identifier I want
to cover and those are spaces.
So, if you see here, we've made
a mockup Touch Bar and we have a
shark item and an angelfish.
And the angel fish probably
isn't that comfortable being so
close to the shark.
Thankfully, the shark is facing
the wrong way so the fish
probably isn't on the menu yet.
But we can go ahead and give the
angelfish some breathing room.
And we can do that by adding a
fixed space small item
identifier in the default item
identifiers array in between the
shark and angelfish item
identifiers.
And we don't have to settle for
small, we can also use a large
one and give it a little bit
more space.
And it's useful to use these
instead of hard coding your own
space, because these are our
system defined values that may
change from release to release,
but they also give your app an
appearance similar to other apps
on the system.
We don't have to stop with fixed
spaces though, we also have a
flexible space identifier.
And the flexible space is
interesting in that it's going
to push the adjacent items as
far away from each other as they
can get.
So, in this case, the angelfish
probably feels a lot better with
that flexible space between it
and the shark.
You might be thinking you could
put flexible space on two side
of an item to center it.
And that's a very reasonable
thought.
If you do that, you're going,
actually, let's say we do that
with our purple circle.
We put flexible space on the
left and right sides of it.
The circle is centered within
the application section of the
Touch Bar, which might be what
you're going for.
But you might also want to be
centering that item on the
actual device, and it's not
there.
We're a little bit to the left.
So, we can fix that by using and
NSTouchBar property called the
principal item identifier.
And we can go ahead and set a
Touch Bar's
principalItemIdentifier to the
identifier of any visible item,
and it's going to go ahead and
actually place that item in the
center of the device.
So, if we go ahead and look at
this example, all the code in
here is stuff we see in our
previous slides except this last
line where we set the
principalItemIdentifier.
And by setting to the shark
identifier, we go ahead and move
and the shark to the middle of
the Touch Bar and lay out the
items left to right like we did
in other cases.
If we were to use the turtle
instead, the shark winds up on
the left side like it would
normally, and the turtle is
centered on the device.
And this plays really well with
flexible spaces and other
things.
Son you can make some nuance
device with that.
And there's additionally types
of NSTouchBar items subclasses
that modify the behavior of the
principalItemIdentifier.
And John is going to go ahead
and cover those as we take a
deep dive into NSTouchBar item.
Welcome John Tegtmeyer.
[ Applause ]
So, Chris gave us an overview
over the NSTouchBar API and how
it's tied to the responder chain
allowing us to provide context
sensitive controls to our users.
He also eluded to this
NSTouchBar item object, which is
the wrap around all the views in
the Touch Bar.
Now, AppKit provides a lot of
subclasses of this item, and
they all offer some really
unique, very cool functionality.
So, I'm here to give us a deep
dive into those items.
NSTouchBar item is a base class
of everything that we'll talk
about today.
That means the properties on
this will be inherited by the
subclass.
The first thing that all Touch
Bar items have is a unique
identifier.
This is what NSTouchBar will use
when looking up your item
through the template items
array, or through the delegate.
Items also have a view or a view
controller.
This is what's actually
presented to your users.
And if you're using the view
controller, this is a good
opportunity to lazily load your
views.
We also have a customization
label.
And this is the string that's
presented in the customization
UI.
And describes what your control
actually does.
I hope you notice one thing that
we don't have here is an
explicit minimum or maximum size
property.
That's because, unlike tool bar
item, which does have these
explicit properties Touch Bar
items are actually measured
using constraints.
That means if you're using
something like an NS button
which has an intrinsic content
size, it will automatically be
sized to fit its title and its
image.
You can also choose to use
inequality constraints to set up
minimum and maximum sizes.
And AppKit will automatically
size you view based on how much
space is available in the
application section.
And you can find out more about
how items are sized at the
"Advanced Touch Bar Talk" later
today.
Now, as I mentioned, AppKit
provides lots of subclasses of
this item.
And we'll talk about each of
these.
We'll talk about the custom
Touch Bar item, pop overs,
sliders, group item, as well as
a few bonus topics at the end.
So, let's get started with the
custom Touch Bar item.
Now, the custom item offers
rewrite properties on everything
that we just talked about on the
base class.
That means you can simply set
the view of the view controller
rather than subclassing your
item.
This is likely the item that
you'll use if you want to show
something like a button or a
segmented control.
Anything that you're familiar
with through AppKit, or custom
container views.
Now, this is also a really great
opportunity to use some of the
convenience constructors that we
introduced in 10.12.
Let's take a look.
In this example, we're going to
create a simple button for Touch
Bar.
We're doing that by creating a
custom Touch Bar item and
providing a unique identifier.
And then we're going to set the
items view to be an NS button
using the title target action
constructor that we saw earlier.
And as Chris mentioned, this
will assign the correct font and
the correct appearance to this
button.
So, we have a great looking
button that's ready for Touch
Bar in two simple lines of code.
This is also true for a more
complicated control.
In this case, this is a
segmented control.
Segmented control also has a
convenience constructor.
And so, again with two lines of
code, my spacing for clarity, we
have a great looking control
that's ready for Touch Bar with
the right appearance and the
right font.
Next, let's talk about popovers.
Popover item is really cool
because it allows you to provide
extra content to your user, but
only when the user requests it.
Popovers have two parts.
The first is the class
representation, which is the
view presented to your user when
the popovers close.
And the second piece is the
popover's NSTouchBar, which
actually takes over the
application section when the
popover is open.
And this lets you use things
like the
principalItemIdentifier, or even
enabling customization.
Let's talk more about the class
representation.
AppKit will provide a default on
for you and you can customize
the way it looks by using the
class representation image, or
label properties.
And you can see an example of
this in the list in alignment
popovers and the formatting
controls.
You can also choose to use
something more custom.
Mail chooses to use a segmented
control.
And if you tap the main portion
of this control, it will
immediately move a message to
the suggest mailbox.
But if you tap the arrow, it
will show a popover with
additional suggestions.
This is actually really easy to
achieve by providing your own
view for the class
representation and then using
the show popover and dismiss
popover methods.
Popovers also have two
interaction models.
First is touch and show.
This happens when the user taps
the class representation.
The popover's opened and it's
sticky allowing you to make
multiple selections.
It's only closed when the user
taps the closed button.
The second interaction model is
press and hold.
And this happens when the user
presses and holds on the class
representation.
The popover's open directly by
the user's finger when possible
and immediately starts tracking
their input.
It's closed when the user lifts
their finger and a selection is
made.
But you'll notice that in these
two examples, the popovers
actually showed different
content.
Touch and show showed several
controls whereas press and hold
only showed a single segmented
control.
And that's because press and
hold is tracking the user's
finger the entire time.
And so, it's best to leave that
kind of interaction to a single
control.
In this case a segmented
control, or even something like
the slider item.
This is easy to achieve because
popovers actually have two
different NSTouchBar properties.
One for the touch and hold
popover and another for the
press and hold.
Press and hold, if you do not
provide an NSTouchBar for press
and hold, press and hold will
not be enabled.
It is possible to provide the
same NSTouchBar object for both
of these properties and that
will work just fine.
But as I mentioned press and
hold is best left reserved for
single things, single items like
a segmented control or a slider
item.
Speaking of the slider item,
let's talk about it.
Now, you might be thinking
what's the difference between a
slider item and a custom Touch
Bar item with an NSSlider as its
view.
Well, let me explain.
Sliders have a few different
parts.
First we have the slider itself.
Then, we have these new value
accessories, which are images
and are actually intractable.
You can tap on them to increment
or decrement the value of your
slider.
We also have a label.
This can make it extra clear to
your users what this slider is
actually controlling.
And it's really useful if you
have multiple sliders in your
UI.
As I mentioned these make really
great content for press and hold
popover.
And that's because the
immediately start tracking the
user's finger, even though the
touch is offset from the knob of
the slider.
That means the user can
immediately start interacting
with it and not go searching
around for the knob for
interacting with the slider.
Let's take a look at what this
actually looks like in code,
though.
First, we're going to create the
item itself.
We're going to provide a unique
identifier.
Next, we're going to assign it
minimum and maximum value
accessories and we're going to
use images that AppKit provides.
And lastly, we're going to
assign a label, because maybe we
want multiple sliders in our UI.
But you'll notice that the
slider is actually taking up the
entire application section.
Well, that's because sliders do
not have an intrinsic content
size.
They're happy to be whatever
size is available in the
application section.
You can change this by adding a
constraint to the slider and
AppKit will check that and
automatically remeasure and
resize the item.
But notice that we're doing this
on the slider itself, and not
the slider items view and that's
because we have a label here.
And if we change localizations
the length of this string will
also change and we don't want to
cause clipping.
Next, let's talk about group
Touch Bar item.
Group item is neat because it
allows you to group multiple
Touch Bar items into a single
NSTouchBarItem instance.
This is because it's similar to
popovers in that it offers its
NSTouchBar property.
An example of this is the
formatting controls above me.
These have actually been grouped
into a single NSTouchBarItem.
There are several reasons you
might want to do this, and we'll
talk about each of these.
When centering multiple items,
there's some tricks you can play
with customization as well as
localization purposes.
If you remember a few minutes
ago, when Chris was talking
about the
principalItemIdentifier, you'll
recall that a single item
identifier is actually provided
as principal.
But what happens if you want to
center multiple items together
like FaceTime is doing here.
Well, you can group these items
to a single group Touch Bar item
and then provide that item's
identifier as the principal item
identifier.
You can also play some cool
tricks with the customization.
If you have a non-customizable
group like we do here, you'll
notice that these items are
actually grouped together.
That means when the user drags
these things into, these buttons
into the Touch Bar, all three of
these will come together.
There's also a single
customization label describing
these controls as the playback
controls.
If you do choose to enable
customization on your groups,
you get some cool behavior there
as well.
In this example, we have two
group Touch Bar items.
Both of them have customization
enabled.
One contains a group of animals
that you might find in the
ocean, and another on a farm.
If I start customizing this,
you'll notice that I'm free to
re-order these items however I
choose within their groups.
If I try, however, to grab one
of the ocean animals and put it
into the farm animals group, it
snaps back to where it was.
Because that would be removing
the item from its group and
that's not supported.
GroupTouchBarItem also has
really cool purposes for
localization.
Now, I'm sure your applications
reach lots of users.
Some of those users might be
native right to left speakers of
languages like Hebrew or Arabic.
And I'm sure your applications
are already flipping were
appropriate for those users.
And we want Touch Bar to reflect
that as well.
A good example of this is
FaceTime's UI.
FaceTime chooses to show a full
screen and a mute button both on
the screen as well as within
Touch Bar.
And you'll notice that the order
of these buttons match.
If I go ahead and change the
language to Arabic, you'll
notice that the on-screen
buttons will actually reverse
their order.
And we do the same in Touch Bar
to maintain that matching order.
But it's important to note that
not everything actually flips.
The escape key and the control
strip stay where they're at
whether it's left to right or
right to left.
And only specific groups of
items should possibly flip.
Such as the center controls
here, which we're flipping to
match on-screen UI.
As well as the image and label
about the incoming call are
flipped.
But the position of that item
did not move to the opposite
side of the Touch Bar.
This is easy to achieve using
GroupTouchBarItem's new group
user interface layout direction
property in 10.13.
You can simply set this to
reflect NSAppuserInterface
LayoutDirection.
Now, I'm sure you're aware
languages aren't just left to
right or right to left, they
also have variable length
strings.
And it's important to remember
that when you're designing your
UI.
In this example, I have a list
of some of my favorite ocean
animals.
And I ran this exact same app in
both English and in German.
In English I was able to fit 6
items here.
But in German I only have 5.
That's because the shark item
actually didn't have enough room
to fit in Touch Bar and so it
was hidden from the user.
Which is really unfortunate for
our German friends.
Now, you might be tempted to fix
this using constraints, tying
each button to be a specific
width.
But that's actually not a great
solution because as we change
localizations, we're almost
certainly going to cause
clipping in one of them.
Now, GroupTouchBarItem actually
has a great way of handling this
for you automatically starting
in 10.13.
And I encourage you to check out
the "Advanced Touch Bar Talk"
later today which will do a dive
into exactly what happens.
Now, we have a few bonus topics.
These are all covered great in
documentation, but we'll mention
them briefly now.
First is the
ColorPickerTouchBarItem.
This allows users to interact
with the color picker right
through Touch Bar.
They can choose the exact color
that they want.
They can even change color
models and your document can
restrict which color models are
supported.
Users also have access to their
favorite color swatches.
So, it's a really great
experience.
We also have a
SharingServicePicker.
This lets you easily share a
document through mail, messages,
air drop, or even third-party
insurance services.
And these are all the same
services available through the
share sheet.
And finally, we have an
NSScrubber, which is actually a
view, not an item.
This could be the view of a
Touch Bar item.
And you can see in an
application such as calendar's
timeline, Safari's tabs or even
the color swatches of the color
picker that we just talked
about.
It's a very versatile, very
fluid control.
And it was designed specifically
for Touch Bar.
You can find out more about this
at the advanced talk, which will
do a deep dive on exactly how to
use this control.
Now, we've covered a ton of
material today.
We talked about the NSTouchBar
API, how it's tied to the
responder chain, how you can use
it to provide context-sensitive
controls for your users.
We've talked about the
NSTouchBarItem and all of its
subclasses that AppKit provides
and their unique functionality.
So, you now know enough to go
adopt Touch Bar in your
applications today.
While you're there, you should
definitely enable user
customization so that users can
get the exact experience that
they're looking for.
And definitely remember to
design you UI with localization
in mind so that all users have a
great experience.
For more information, you can
check out our developer website.
We have some related sessions
you might be interested in.
"Choosing the Right Cocoa
Container View" will look at
when you might want to choose a
grid view over a stack view.
And this could be important
because you could use one of
these container views as the
content view of a TouchBarItem.
We also have the "Advanced Touch
Bar Talk" which we mentioned
several times, which will do a
dive into extra functionality of
Touch Bar.
Thank you all so much for
joining us today.
Enjoy the rest of your
conference
[ Applause ]
.