My name's Justin.
I work on UIKit.
And I am here to show you how you can go beyond the basics
and really take your tvOS app to the next level.
So to do that, there's a few things that I want
to talk to you about today.
And the first is event handling.
What kind of events is your app going to receive,
and what are the best ways for you to handle those events?
Then I'd like to talk about layered images.
This is a user interface element that's unique to tvOS,
and we'll show you how to really take advantage of it.
Thirdly, we'll talk about scrolling.
Scrolling on tvOS works a little bit differently
than scrolling on iOS.
And we'll show you how you really take control
And finally, we'll talk about text input
and how you can use the system keyboard
to accept text from users.
So let's get started and dive right into event handling.
So when it comes to event handling,
there are a few overall best practices that I want to share
with you right off the bat.
And the first is, is that when it comes to allowing your users
to navigate your application and to move focus from one item
to another, you don't need to write any
of your own event handling code at all.
The focus engine is going take care of all of that for you,
including handling different kinds of events based
on what kind of input device the user is currently using.
So it'll take care of all of that for you.
Secondly, if you decide you do need to start handling events,
I recommend that you start with UIGestureRecognizer.
Not only to have a really expressive API,
but it'll also help ensure all of the gestures and interactions
in your app are going to be consistent
across all the system apps and other apps.
And finally, as you are designing the interaction model
for your application, keep in mind
that not every input device can generate every kind of event.
So for example, a user might be using a game controller
to navigate to your application.
And game controllers can't generate touch events.
So you might not want to use touch events as the only way
to interact with your application.
So keep that in mind as you are designing your app.
So speaking of touches, we have touches
on tvOS using the touch surface on the Siri remote.
And we deliver them to you using UITouch, which is an API
that you might recognize from iOS.
And a touch represents the contact between a user's finger
and that surface on the remote.
This is just like the iOS version.
It has the location and all the other properties
that you are used to.
But there is one important difference between touches
on tvOS and touches on iOS.
A touch on iOS is happening directly
onto the user interface.
The user is physically touching the UI.
That's not the case on tvOS.
The user interface is 10 feet away,
and the user is touching their remote.
And so we bucket these into two different categories.
We say the ones on iOS are direct touches,
and the ones tvOS are considered indirect touches.
And we have this touch type called UITouchTypeIndirect
to help you tell the difference between the two of those.
And because of this indirection, if you were to ask the UITouch,
"What's your location onscreen?"
on a direct touch interface that's a pretty obvious answer.
We give you a location that maps exactly
where the user's finger is on the screen.
But on tvOS, the user isn't touching the screen.
What location should we report for the touch?
And so what we do in this case is that no matter
where the user's finger begins touching the remote,
we always deliver the touch to your application
as if it had begun directly in the center of the focused view.
And this is really great, because it means
that any gesture recognizers or event handling logic
that you might have attached
to the focused view will always have an opportunity
to participate in the gesture.
One thing that we don't expose is the absolute location
of the user's finger on the track pad.
And there is a few reasons why we do that,
but one of the really important ones is that that we want
to discourage pointer-based UIs on tvOS.
We don't want to see anything like mouse cursors
or anything like that.
We'd really rather that applications stick
to the focus interaction model that we have created.
So in addition to touches, there is also another kind of event
that you'll get on tvOS; and these are called presses.
And presses are delivered using the classical UIPress.
And a press represents an actual physical hardware button
that the user is interacting with.
And not all of those buttons are simply pressed or not pressed.
Some buttons, like those on game controllers,
are pressure sensitive.
But we can actually detect how firmly the user is pressing the
button, and we can deliver that information to you.
You can recognize presses using UIGestureRecognizer,
including things like TapGestureRecognizer
And we have low-level press handling events
that follow the same pattern
as a low-level touch handling event.
So we have pressesBegan, which fires as soon
as the user begins depressing the button.
We have pressesChanged, which will be delivered
if it's a pressure-sensitive button
and the amount of pressure changes.
And we also have pressesEnded and pressesCancelled.
And just like touchesCancelled,
yes you really do have to implement it.
There's one thing to know about these methods,
which is that press events
because they don't really have a location they get delivered
directly to the focus view.
And they go up the responder chain from there.
They won't go to any child views of the focus views.
So keep that in mind when you are deciding what view
to attach gesture recognizers to.
Okay, so we are talking a lot about presses.
Let's go through some of the press types that are available
to you and what buttons will trigger them
on various input devices.
So I want to show you the Siri remote, the Apple remote
from previous-generation Apple TVs,
and I want to show you game controllers.
And I don't have room on the slides here,
but keep in mind presses can also be generated
from programmable universal remotes and also
from Bluetooth keyboards.
So there is a lot of ways to get presses.
Probably the most common press type you'll encounter
And this is the press type that represents that the user wants
to activate a control or select
on a CollectionView cell, something like that.
And on the Siri remote,
that's the button that's actually underneath the touch
surface on the remote.
On the Apple remote, that's the silver circle.
And on game controllers we use the A button
to generate this press type.
Another really common press type you'll encounter
And this is the press type
that indicates the user wants to go back.
They want to dismiss a presented view controller
or even dismiss your application entirely
and return to the Home screen.
And in all three of these on the screen,
that'll be the button that says Menu.
And on game controllers, we will also use the B button.
And finally, there is UIPressTypePlayPause.
And this is obviously useful for pausing or playing content,
but it can also be used as sort of a shortcut
in addition to Select.
So if the users focus on, say, a movie poster,
pressing the Select button might show the details for the movie.
But pressing Play/Pause will just jump straight
And so that's the icon that has the --
or the button that has the Play/Pause icon on it.
And on game controllers we'll use the X button
to generate that press type.
Okay, so to round things
out there is just a few more press types,
and these are directional presses.
So we have up, down, left, and right arrow presses
that can be generated.
On the Apple remote we use the four directional buttons.
On game controllers there is lots of ways to get these.
So we'll use the D pad.
We'll also use the directional analog stick.
And we'll even generate left
and right presses using the shoulder buttons
on the game controller.
Now there aren't any discrete hardware buttons
for these arrows on the serial remote, so you might think
that it's not possible to generate these there
but that's actually not true.
If you do a touch tap you are not pressing all the way
down on the Select button but just touching
on these four cardinal points on the surface.
Then UIKit will detect that
and actually generate arrow presses for you.
And this is a really convenient way to navigate
through your user interface exactly one item at a time.
So just because the user is using the Siri remote,
that doesn't mean that they can't generate arrow presses.
Okay, so I promised you that you can use gesture recognizers
to recognize these.
And I won't go through these in detail, but I just want
to show you a few quick examples.
You know, we can use the TapGestureRecognizer there
on the top.
We can even do a long press just like you might do to go
into the editing mode on the tvOS Home screen.
And there at the bottom I can even adjust the number
of taps required.
So now I am listening for a double tap on the Select button.
Okay, let's talk about one button in particular,
and that's the Menu button.
The Menu button has some interesting behavior on tvOS.
It kind of has to play two roles.
Not only does it need to be useful inside
of your application, because we need to do things
like dismiss view controllers or pop things off
of a UINavigationController.
But it also needs to have system-level behavior.
And eventually your app needs to dismiss --
be dismissed so the user can return to the Home screen.
And your user is going to be really frustrated
if that's not possible.
And we can think that this is so important,
that this is something that App Review looks for specifically.
So if your application can't be exited
by pressing the Menu button, you might fail App Review.
And we don't want that to happen.
So how does this work?
How do we get it so that the Menu button can both be captured
by your application but also used by the system?
Well the technical thing that needs to happen in order
for your app to gracefully resign and go back
to the Home screen is that when the Menu button is released,
the pressesEnded event needs to go all the way
up the responder chain if you are received by UIApplication.
If that doesn't happen, your application won't resign.
Now sometimes that's exactly what you want.
So if you are deep into UINavigationController,
and the user presses the Menu button, they don't want
to resign your app; they just want to go back
to the previous view controller.
So in that case, there might be a TapGestureRecognizer that's
listening for the Menu button.
And if that recognizer begins to recognize,
it'll send pressesCancelled to the responder chain.
And in that case the application won't exit,
and then UINavigationController can hop off
that view controller.
So it's okay to not always send pressesEnded
to your application.
You just need to make sure that it is possible when it becomes
at the appropriate time.
So to do this correctly, we obviously recommend
that you start with gesture recognizers.
And when you no longer are interested
in handling the Menu button, you need to make sure
that GestureRecognizer gets out of the way.
And so one way to do that is just remove the
GestureRecognizer from the view.
You also disable the gesture.
So gesture recognizers have a property called enabled.
And if you set that to false,
then the gesture will get out of the way.
And if you don't want to do either one of those,
there is UIGestureRecognizer delegate API called
And you can implement this, and then for every press
of the Menu button you get the opportunity
to decide right then whether or not you want
to handle the gesture.
If you are implementing the lower-level press handling
methods, in your pressesEnded implementation decide whether
or not you want to handle the event.
And if you do want to handle the event, then don't call super.
But if you are not going to handle the event, then make sure
that you do call super so that it can continue to go
up the responder chain
and UIApplication has the opportunity to receive it.
Finally, if you are writing a game,
it's common that you only really have one view controller,
which is the one that shows your game.
And so in that case you might want to look
at using GCEventViewController.
Now it has this property,
And what this does is that when the user is navigating
through your app using a game controller,
not only are events going to the game controller framework,
which you are probably already using your game.
But they also can generate UIKit events,
like these presses and other things.
And when you are in the middle of game play,
you are probably not interested
in receiving the UIKit version of those events.
So if you set controllerUser InteractionEnabled
to false during your game play, then pressing, say,
the Menu button won't instantly exit your application.
And instead you'll be able to capture it
and take care of it on your own.
But when the user gets back to the root menu of your game,
you are going to want to turn this back to yes
so that pressing the Menu button can exit your application.
So that is event handling.
Let's talk now about layered images.
Layered images are this user interface element that's really
unique to tvOS.
And there are these images
that you've probably seen in all the demos.
And they can have up to five layers within them,
a parallaxing content that moves.
And these are required for application icons.
So your application icon on tvOS has to have
at a minimum of two layers.
So you'll have to be at least a little familiar with this format
if you are going to be on tvOS and they're interactive.
As the user moves their finger around on the Siri remote,
the image moves in time with their finger.
And this is more than just eye candy.
This helps the user to realize
that their inputs are being received and helps them
to anticipate focus movement before it happens.
And they're animated.
So they have a lot of great animation that comes built-in,
especially like when they become focused.
And we'll show you how you can coordinate those animations
to really make your app come to life.
Okay, so let's talk about that interactivity.
So the video that I just showed you, that's a UIImageView.
And if the UIImageView becomes focused,
then it'll automatically give you
that great floating appearance
if you have a layered image inside of that ImageView.
But it's often the case
that a UI image is not the control that's actually
Images are typically a component of a larger control,
and in that case the larger control is going
to become focused.
So how do we get this floating appearance
if the image isn't what's becoming focused?
Well it doesn't have to be focused.
We have this property that we've added
to UIImageView called adjustsImage
And if you set this to be true, then if any parent view
of the image becomes focused,
then the image will automatically get
that floating appearance
and begin reacting to the user's input.
And these images can also have a pressed-in state.
And so this is slightly different
than the normal default state,
where they are sitting back on the screen.
They kind of have this sort of smooshed-in appearance
as if the user is physically pressing them down.
And you can trigger this manually
by setting the isHighlighted property on your ImageView
to be either true or false, and that'll turn
on or off that effect.
And you might want to do this in your control subclass
when the user starts pressing the Select button, for example.
But there are a few cases where we cover this for you
and you won't have to do this manually at all.
And those are images that are inside UICollectionViewCells
and images that are inside of custom UIButton.
In those cases you don't have to manage isHighlighted property
at all; we'll take care of that for you.
Okay, so we talked about animations.
So let's look at that a little more closely.
So one of the things that happens
when these images become,
in their floating appearances they get bigger
or they look like they get bigger.
And you might have to use it on your nearbys.
You might want to move it out of the way,
like you have a label underneath of a movie poster.
And you can constrain those using Auto Layouts.
So, you know, if I have this ImageView here,
let's say that I have sized the ImageView
to be the same size as the image.
Then you can constrain to the frame of the image.
But when it becomes enlarged, the frame doesn't change
but the visible extent of the image does.
And so to find out how large the image will be
when it becomes focused,
we expose this layout guide called focusedFrameGuide.
And you can attach other constraints
to that layout guide, and that way those views will be far
enough away from the image that they won't be clipped by it
when it becomes larger.
So let's run through this.
So I have my ImageView here, and I have this red outline
that represents the frame of the UIImageView.
And when it becomes focused it's going to get bigger,
but the frame is still at that red outline.
And so now this dotted outline shows
where the focusedFrameGuide is.
And that focusedFrameGuide will always be there,
even if it's not currently focused.
And so you can choose which one of these you want
to attach your layout constraints to.
Or you may choose to change
which constraints are active based on whether
or not the element is currently focused.
And if you do that you should really use the coordination API
that we expose on the focus update context to make sure
that the animation happens in time with the system animation.
The system animation has a lot of subtlety in it in terms
of what exactly the timing is.
It depends on how quickly the user is swiping
or how far off-screen the view is focused
at the moment it became focused.
So it's not really possible to get target values into your app.
You are going to need to use the coordination API to make sure
that your animations will match the system animations.
And to show you how to do that,
I'd like to invite Randy onstage to give you a demo.
Thank you Justin.
So today I am going to walk
through those two common cases we have
with adding interactivity to layered images.
And first we are going to look at a UIButton.
And second we are going to look
at a custom collection view table cell.
So to get started, I have got a project here opened in Xcode
with an asset catalog that has some layered images.
And I just have a ViewController subclass here.
And we are going to drag out a button --
into the canvas and inspect it to give it an image.
And we'll delete its title.
And then we'll add a couple of constraints
to center it horizontally and vertically.
And then we'll update that Buttons frame
to match those constraints.
You can do that with this menu down here,
but I usually the keyboard shortcut Command Option Equals.
And if you look closely, there is a little bit
of extra space around the button.
Those are the edge content insets.
We don't want those, so we can just delete them.
So that looks about like what we want.
So we'll build and run and see how it behaves.
Now I am using the tvOS simulator here,
but I have paired a Siri remote with Mac
so you can get a good feel
for how the interaction is going to work.
And my finger is pressing down on the Select button,
but it's just doing this darkening effect and sort
of doing that sort of smooshing in.
And when I move my finger on the digitizer,
it doesn't react to my touch.
So let's make that better.
To do that, I am going to open up the Assistant Editor
for our ViewController subclass and drag
out an outlet for the button.
And then in viewDidLoad,
I am going to grab the ImageView from that button.
And I want to turn on that property that Justin told us
about adjustsImage WhenAncestorFocused.
And now if I build and run, you should see
that the button responds to my finger on the remote.
And it pushes in when I click on it.
But we still have an issue here because the edges
of this button are clipped.
And that's because by default,
the button's ImageView has clipsToBounds turned on.
So we just turn that off.
Build and run again.
We should get exactly what we are looking for.
It's a great interactive layered image that moves
around with my finger and smooshes it
when I press on it, great.
Let's do something a little more involved.
I have another project here,
and this one has a CollectionViewController
subclass in it.
And I have gone ahead and configured the sizing parameters
of the CollectionView according
to the Human Interface Guidelines for tvOS
for a six-column layout.
Those guidelines tell us we want a cell width of 250 points.
And I know, based on my designs, I'll need 450 points vertically
for the content of the cells.
And the guidelines tell us
for a six-column layout we need 48 points
between cells horizontally and at least 100 points
between cells vertically.
And finally, to stay within the safe areas of a wide range
of TVs, we want to leave 60 points at the top and the bottom
and 90 points on the left and the right.
And those numbers are also in the guidelines.
So let's take a look at the cell itself.
I have already given it a custom class and a reuse identifier.
And we are going to zoom in a little bit
and add some custom subviews.
First we'll drag out an ImageView.
And then we'll drag out a label.
Now I'll add some constraints to lay out these views.
We want the ImageView to hug the top left and right edges.
And we happen to know that all
of our images have the same aspect ratio.
So I'll also add an aspect ratio constraint.
And then I'll edit that aspect ratio constraint
to match our images so they have a ratio of 2-to-3.
And then I'll add some constraints to my label.
I'll Control-Drag from the label to the ImageView
to add a horizontal centering constraint.
And then I also want my ImageView the top
of my label will be 15 points from the bottom of my ImageView.
So I'll add a constraint between those things.
Now that we have added all those constraints,
we can do Command Option Equals to get everything
where it's supposed to be.
And finally, that font is a little small.
So I am going to bump it up to Body style, nice pick.
And we've got some outlets for the ImageView on our poster.
So we'll just hook those up and the label.
Now we'll take a quick look at our CollectionViewController.
You can see I have just implemented number of items
in section, and cellForItemAt indexPath.
So if I build and run, we should get basically the layout we are
But we'll see what the behavior is like.
So this is pretty much the layout I was looking for.
It's all the right things.
But right away you can't tell which item is focused.
And when I click, you can't see which cell I am selecting.
So let's take care of all those things.
Now first, to see where the focus is we are going to go
into Interface Builder and select our ImageView and check
that adjustImagewhenfocused check mark.
And that'll be enough to get our cells
to start responding to focus.
As you can see, it's big, and it reacts to my touch;
and when I click it pushes in.
But the labels are overlapping on the bottom.
They are not responding to the change in the focus size.
So to do something about that, we are going to open
up our custom cell class in the Assistant Editor.
And first we are going to drag out an outlet
for that vertical constraint between the top of the label
and the bottom of the ImageView.
So we'll add an outlet for that, and we'll call
that the unfocusedConstraint.
And then I'll add another property
for the focusedConstraint.
We'll set that focusedConstraint up in awakeFromNib
to be the labels.topAnchor
relative to the imageView's focusedFrameGuide bottomAnchor
plus those 15 points.
Then in updateConstraints we'll set the focusedFrame --
we'll make the focusedConstraint active when the cell is focused.
And we'll make the unfocusedConstraint active
in the opposite case.
Finally, in didUpdateFocus, we'll invalidate our constraints
by calling setNeedsUpdateConstraints.
And then we'll add a coordinated animation
by calling addCoordinatedAnimations.
And inside there, we'll call layoutIfNeeded.
And that'll be enough that now when we build and run,
we should see the label has move down below out of the way
of the focused poster.
And when I move from one to the other, they all animate
out of the way and back to where they should be.
So remember, use focusedFrameGuide
And don't forget to turn
on adjustsImage WhenAncestorFocused
to get these effects.
With that, back to Justin.
Thanks for that awesome demo, Randy.
So you can see how easy it is to really take advantage
of this unique user interface element
to really bring your tvOS apps to life.
All right, let's change gears a little bit now
and talk about scrolling.
So scrolling on tvOS is a bit different than scrolling on iOS.
And it has to do with those indirect touches.
So when the user is scrolling in ScrollView on iOS,
they are physically touching the ScrollView.
And as they move their finger, it will adjust the offset
of the ScrollView to match the motion of their finger.
But that's not really how it works on tvOS.
On tvOS, you are not touching the screen,
but you are also not manipulating the scroll
What you are really doing is you are changing what's the
Then as the focus item changes, the focus engine will detect
that and it will automatically scroll any scroll views
as needed to make sure that the focused view will always
The focus engine will choose the best offset that it can
for you based on the size of the view
and the size of the ScrollView.
But there are some times where you want to take control
of what offset that it's going to send you to.
So for example, one common customization that people want
to do is they want to that the focused view is always centered
within the bounds of the ScrollView.
And you can do that.
And the way you can do that is
with the UIScrollViewDelegate method that you might recognize
from iOS which is scrollView WillEndDragging,
And the final parameter there, the targetContentOffset,
is a pointer to a CGPoint.
And that point represents the offset
that the focus engine will scroll you
to if you don't do anything else.
That's the offset that it shows for you automatically.
But if you'd like to do your own calculations and decide
for yourself what you want the scroll offset
to be, you can do that.
Make your calculation about what offset you'd like,
and then store the value into the point that's pointed
to you by that pointer.
And then the focus engine will scroll there instead.
And you'll get all the great system animations that come
with that, but to your selected offset.
But it's not to say that direct manipulation is always bad
or is never a good idea on tvOS.
There are some cases where you'd want to do that.
And so some of the situations that call for that are things
like you have a lot of full-screen content.
Maybe you have full-screen photo gallery,
where the photos go completely to the edges of the screen.
So one example from UIKit is UIPageViewController.
When you have a UIPageViewController,
it doesn't do the focused scrolling.
And instead, you are directly manipulating the ScrollView
content of the PageViewController.
There are other cases where you have a lot of scrolling text.
So it's another good place where you might want
to do direct manipulation.
Basically, anytime where it's not clear what ought
to be the focused item, and you wouldn't be able
to see what the next focused item would be,
and those are good situations to do direct manipulation.
So if you want to do that, you don't have
to write your own gesture handling code.
You can reuse the pan gesture
that already comes on ScrollView.
The trick is that scroll views are configured to only listen
for direct touches out of the box.
And the Siri remote is generating indirect touched.
So you just need to get this pan gesture recognizer
and convince it to listen to indirect touches.
We also have a directional press gesture recognizer,
which is only on ScrollView on tvOS.
And this is listening for those arrow button presses.
So that way a user who is not using a device
that he can do touch input can also scroll ScrollViews.
And this gesture is disabled by default
because we would rather have this arrow presses manipulate
focus instead of manipulating the ScrollView offset.
So you'll have to enable it.
And this is the code that you can use
to do both of those things.
So we are getting
to panGestureRecognizer from the ScrollView.
And we are telling it that we'd
like to listen for indirect touches.
And we are getting
that directionalPressGesture Recognizer,
and we are telling it that it should be enabled.
And if you do this, then all of those events that come
into the ScrollView will directly manipulate the offset
of the ScrollView.
And it's actually possible
to combine this direct manipulation technique
and the focus interaction technique.
And to show you how you can do that,
I'd like to invite Kevin onstage to give you a demo.
Hi. I'm Kevin Hiscott, and I'm an engineer on tvOS.
We are going to look at a sample view controller
that presents terms and conditions text in a text view.
TextView is a subclass of ScrollView.
So we can take a look at how to add direct manipulation to it.
Let's head over to my ZIB [phonetic]
and see what I have set up so far.
I have a text view with very lengthy lower mid sub [phonetic]
pasted into it.
And if we go into our application, we can see what
that looks like in the app context.
When I present my ViewController,
we can see along the bottom edge
that the text is actually clipped.
And if I try swiping the Siri remote,
the text does not scroll.
Well let's go improve that.
Let's head over to my ViewController.
And in viewDidLoad we are going
to grab the outlet I have created to that UITextView.
I have called it messageTextView.
And on messageTextView and any ScrollView,
there is a panGestureRecognizer.
And we are going to change its allowed touch types
to include the indirect touch type.
As Justin mentioned, those are the touches created
by the Siri remote.
The second thing we are going to do is set isSelectable to true.
This will allow the text view to be focused, to become focused,
and receive these events.
Let's build and run and see how this works.
Now when I present my ViewController,
I am actually able to directly swipe to scroll the text up
and down with the Siri remote.
Great direct manipulation.
The other thing any good terms
and conditions ViewController needs is a way for the user
to either accept or reject your conditions.
So to do that, let's head over to my ZIB and drag
in a couple of buttons.
I am going to label one Disagree and the other one Agree.
Let's build and run and see what happens.
What I hope to happen is for our focus to move horizontally
with horizontal swipes, and for vertical swipes
to still scroll the text view.
However, when I present my ViewController I can see
that vertical swipes does move the text; however,
if I swipe too far down, focus actually moves
down into the buttons, and I can no longer scroll my text
until focus moves back into the text view.
This isn't exactly the behavior I was looking for.
Let's head back to my ViewController.
And we are going to disable isSelectable.
We don't actually want the TextView
to be a focusable element onscreen.
Instead, I am going to show you a little trick.
We are going to grab the panGestureRecognizer
and actually add it to our ViewController's view instead.
This will allow the message TextView to receive events
without being focusable itself.
Let's build and run and see how it behaves.
Now when I present my ViewController,
we can see that the Disagree button immediately
And that's because the text view is no longer focusable.
I can swipe the Siri remote left and right to move focus.
But any time I can swipe up and down to move the text.
Great this is looking really good.
The last thing we need to consider
on tvOS are directional press type events generated
by other input methods like game controllers,
keyboards, or IR remotes.
And we make this really easy to support on tvOS.
Let's head back to my view controller, and we are going
to grab the directionalPressGesture
Recognizer from our messageTextView and enable it.
This will allow scrolling to occur
with those press types generated on those other devices.
The last thing we are going to do is move
that GestureRecognizer onto our own view, just as we did before.
Let's build and run and see how this all comes together.
Now when I present my terms and conditions,
I can both swipe left and right to move focus,
but I can also tap left and right to move focus
with the directional press type events generated
on the Siri remote and all the other devices.
I can swipe up and down to change the content offset,
but I can also tap up and down to incrementally scroll.
Great! This is a fully functional terms
and conditions ViewController for tvOS.
Thanks so much for your time.
And I can't wait to accept all the terms
and conditions in your apps.
Back to Justin [applause].
All right, let's move
on to our final topic, which is text input.
So we have this great system keyboard on tvOS.
And there is a lot of features that are only available
if you are using the system keyboard.
I want to go through just a few of them for you.
One of them is dictation.
So the user can just speak into the Siri remote
and their words will show up on the screen.
We also support Bluetooth keyboards.
So if you pair it with a Bluetooth keyboard,
and you just type right on there.
We have the new Apple TV Remote app
so that users can pair their phone with their TV
and they can type right on their phone's keyboard
to send text to the TV.
There is also a lot
of localization details the system keyboard takes care
of for you.
And it also automatically changes its layout based
on the input device the user is using.
So there is the linear layout
that you are probably most familiar with,
but there is also a grid layout that we'll use
if there is no Siri remote paired with the TV.
These are a lot of great features that are only available
in the system keyboard.
And if you are not using the system keyboard,
then users won't be able to take advantage of these features.
So we discourage you from trying to roll your own keyboard.
Really stick to the system keyboard
so that users can enjoy all these great features
that are only available through the system one.
Now there are some ways that you can customer the built-in
And one way that you can customize it is to add some
of your own views to the keyboard
that will appear alongside of it.
And you can use some API that's on UIResponder
that you might recognize from iOS.
There is the inputAccessoryView
and the inputAccessory ViewController.
And if you assign to these properties on the text fields
that you are wanting to edit text in,
then when the keyboard appears you can show some
of your own views right there alongside the keyboard.
And I'll show you a screenshot of that here in just a second.
And finally, I want to point out one change
in behavior that's happened between tvOS 9 and tvOS 10.
UITextField has this property called keyboardAppearance,
and you can set to unspecified light or dark.
And on tvOS 9, if you set it, say, to dark,
then not only would the keyboard itself be dark
when it presents itself, but the text field would also be dark
as it's sitting there on the screen.
Well now in tvOS 10 we have this new appearance API.
And so the entire system can respond to light or to dark.
And so now what we do on tvOS 10 is
that this keyboard appearance property will only affect the
keyboard, and the appearance
of the text field will now be dictated
by the larger tray collection in UPI.
Okay, so here's the screen shot I promised you.
So in this case I have created just a regular text field,
and I gave it an inputAccessoryView.
And I put a red border on it so you can see where it is.
And those UI labels in there are there are totally custom.
And I just put them in there so you can add any kind
of accessory views that you'd
like that could appear right above the keyboard.
Now another great way that you can get UI on the screen
at the same time as the keyboard is to use SearchController.
And you use some APIs you also might recognize from iOS,
and that's UISearchController.
So we have the keyboard, and the search results appear below it.
And this also automatically adapts.
There is a grid-based layout and a linear-based layout depending
on the input device the user is using.
And you can even embed this inside
of other view controllers.
SearchController usually wants to be presented modally and take
over the whole screen.
But you can embed it inside of another search --
another view controller by using UISearchContainer
And I'll show you a code sample of that, just a few slides.
You provide your own custom view controller for search results.
So the visual appearance of the search results
and the interaction of them is completely up to you.
You can do whatever you want.
You might use a collection view, or maybe you'll use a split view
that has a table view and a collection view if you want.
Any other things you'd like --
it's totally up to you for that view controller.
So here's a quick sample
of how you might embed a search controller inside
of something else like, say, a tab bar controller.
So I have got my custom ViewController class here.
And in viewDidAppear I am going to create a searchController.
I want to make sure I don't do this twice, so I am checking
to make sure I haven't done this already.
Then I am creating my UISearchController
and telling it view controller to use for my results and who
to contact as the search query changes.
Then I am going to wrap that inside
of this UISearchContainer ViewController.
And this allows me now to take this container,
and I can do regular ViewController containment
And then I am going to add it as a ChildViewController.
And if you do something like this, then you'll be able
to easily use a search controller inside of a tab bar,
much like some of the system apps on tvOS.
And that is text input.
So in summary, one of the things that we want you
to take away from this talk.
First one is, when you are doing Menu button handling,
Keep in mind that you don't want to interfere
with the system gestures.
When you are working with layered images, take advantage
of the layout guides that we have given you
and the coordinated animation API to make sure
that your views can move around in tandem
with the system animations.
If you want to do direct manipulation
on ScrollViews you don't have to do any
of that handling code yourself.
Just reuse the pan gestures that already come built in.
And finally, take advantage of the system keyboard to make sure
that your users are getting all the features they can
when it comes to text input.
So for more information about this talk,
you can visit this URL,
where you'll find links to documentation.
We have got a bunch of other sessions
that are coming up this week.
I want to call up two of them in particular
that are both about UIKit on tvOS.
So have a great rest of the conference.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.