Transcript
[ Music ]
[ Applause ]
>> Hello everybody.
This is modernizing your UI for
iOS 13.
I'm David Duncan.
I'll be joined on stage shortly
by my colleagues Russell, Kyle,
James, and Mohammed.
In this section, we're going to
talk about six things.
Preparing your applications for
Flexible UI.
Improvements that we've made the
appearance of Bars and
Presentations, new Features
available to your applications
for searching, and new Gestures
that you can adopt to make your
apps more productive and to take
care of cases that you haven't
been able to do before.
And finally, we're going to go
over those new contextual menu
APIs that were hinted at earlier
this week.
And so with this, let's talk
about Flexible UI.
So, the first step to being
flexible is what your users
first see when they launch your
application.
Storyboards have been the
preferred way to specify your
Launch UI since iOS 8.
But there's also been another
alternative that we've been
supporting since the beginning
of iOS, and that's Launch
Images.
Launch Images require you to
specify an image for every
screen size you support and
revise whenever we introduce new
screen sizes.
And that's not very flexible.
And so, this spring, April 2020,
applications that linked iOS 13
SDK must provide a Launch
Storyboard in order to be
accepted at the app store.
You will no longer be able to
submit with only Launch images.
So, if you haven't adopted
Launch Storyboards yet, now is a
fantastic time to do so, and
that leads on to the next change
that you may have also already
heard of, which is that in the
past if we introduce new
hardware with a new screen size,
your apps were letterboxed.
Well, we're not going to be
doing that anymore either.
So, if you application is built
against the iOS 13 SDK, then it
will always be displayed at the
native full-screen resolution of
the screen.
So we expect that any
application built against iOS13
will use the appropriate APIs to
ensure correct layout at any
size.
Now, for those of you building
iPad applications, this also
applies to split screen
multitasking.
So, we are going to expect that
most applications, unless you
need to provide a truly
immersive experience, are going
to support split screen
multitasking, so that you can
have your app in any size next
to any other application that
might be running that the user
has chosen.
Now, if you're not certain if
you can support all these
resizing modes and everything
else, another thing you might
want to try, especially if you
have an iPad app, is just
building for the Mac, with new
supports that we're adding in
macOS Catalina.
And you can just do that at your
desk to make sure that you
resize nicely for any size.
So, to sum up all that before,
adopt Launch Storyboards.
They're going to be the way to
get that Launch UI when the user
first launches your application.
Make sure your application
properly lays out to support any
size, whether it is the smallest
iPhone to the largest iPad.
And finally, make sure that your
iPad applications also support
Split Screen Multitasking.
Because all of this is going to
be required by April 2020.
And so with that, let's
transition to Bars.
So, if you look at your phone
after installing the beta,
you'll see this is how
nav bars now appears.
When you scroll all the way up
to the top, we drop out the
background, and when we scroll
something underneath, we bring
it back in smoothly and
transparently.
Similarly, on iPad, if you have
split view controller, we do
this independently for both
sides regardless of if the
details support large titles or
not, and they independently
respond.
So, one background comes in or
the other, depending on the
scroll position.
Now, you might be asking, how do
I adopt this?
How do I make sure this works
cleanly in my application?
Well, the adoption story is
easy.
You link against iOS 13, you get
this for free.
But how to make that work
beautifully in your application
might require a little work, and
that's where we have new
appearance customization APIs to
help you do this.
So, let's take a look at what it
might look like to customize a
navigation bar in the new
appearance API.
So, first thing we're going to
do is create the object that
actually represents the
appearance,
UINavigationBarAppearance .
This is a subclass of
UIBarAppearance, and it
encapsulates all the
customization options for
UINavigationBar.
In this case, we're going to
actually make the navigation bar
use an opaque color, and so
we're going to use the default
values provided by
configureWithOpaqueBackground.
That will make your navigation
bar's background conform to
light and dark mode with an
appropriate opaque color.
Now, in this particular case, we
also wanted to change the label
color.
And so, we can set
titleTextAttributes and
largeTitleTextAttributes, and
we'll just give them a custom
color that we'll use, another
dynamic color, just so that we
work great in light and dark
modes.
And finally, we will attach the
navigation bar's standard
appearance.
So, what is that
standardAppearance?
Well, let's take a look.
The navigation bar, when it's in
its size without a large title
is in the standard size, and
that's what standardAppearance
represents.
In addition, if you don't
specify any other appearance
configuration, we'll use that as
the basis to form defaults for
the other two, which I'll talk
about in a moment.
So, if you use a smaller iPhone
in Landscape, you get the
compactAppearance, and that's
what that represents, quantities
for that.
And we saw earlier that in iOS
13 the navigation bar dropped
its background to transparent
when you pull down at the top of
a scroll view.
And so that is the
scrollEdgeAppearance.
Whenever a navigation bar is
associated with a scroll view,
which is pretty common in your
apps, if you're at the top of
that scroll view, then we'll use
the scrollEdgeAppearance instead
of the standard appearance.
The default is to use a
transparent background, and
that's why you get the seamless
appearance that we've got new in
iOS 13.
In addition, you can also
customize the appearance of your
bar button items, and so the
buttonAppearance for plain items
and the doneButtonAppearance for
done items.
Now, we could have stopped
there.
You got your navigation bar.
It's customized.
It's great.
But we decided to also bring
this to Toolbar and TabBar so
that you can customize all your
bars in a very similar way with
each of those classes using
their own subclass of
UIBarAppearance to do their own
customized work.
Now, ToolbarAppearance is
actually just a subset of
properties relative to
navigationBarAppearance, so it's
not too interesting to continue
further with, but
TabBarAppearance is a little bit
different, and that's because
TabBar is also a little
different.
So, with a TabBar, you have
additional customization options
for these three layout
appearance, the
stackedLayoutAppearance, the
inlineAppearance, which you'll
see on iPads, and the
compactInlineAppearance, which
you'll see on smaller phones.
And so, you can put all that
together and get new appearance
customization for all of your
bars.
But there's one more thing.
If you look at the new reminders
app, when you navigate into a
list, this title color changes
to match the list.
The way they do this is they use
per navigation item appearance
customization, which allows you
to specify an appearance based
on the navigation item that you
pushed onto the navigationBar.
Navigation items are also
associated with navigation, or
with view controllers, and so
pushing onto a navigation
controller will naturally use
that.
So what does that look like?
Well, the navigation item has
the same properties that the
navigationBar has.
So a common thing to do is to
just take the standard
appearance from a navigationBar,
make a copy of it so that we are
disassociated from that
appearance, and make whatever
changes you want.
If you want this to be
transparent, there's a configure
transparency that you can use.
You can change bar button item
appearances, etc., etc. And then
you assign it to the navigation
item.
And once you've done that,
whenever the view controller and
navigation item is current, we
will use that appearance instead
of the navigationBar's base
appearance to make sure that you
can customize your navigationBar
for whatever view controller
gets pushed.
And so with that, I'm going to
bring on Russell to talk about
presentations.
[ Applause ]
>> Thanks David.
Hi everyone.
I'm Russell, and new in iOS 13
we have a standard design for
presentations that I am so
excited to tell you all about.
For example, if I'm here in the
contacts app and I tap plus to
add a new contact, we have a new
presentation style that looks
like this, rather than the full
screen presentation that we had
before.
You can see that the root view
controller's view is not as
scaled down and not removed from
the view hierarchy.
The layering of this design
gives your users a sense of
context about where they are in
your applications, and the
rounded top appearance serves as
a signifier that these
presentations can be
interactively dismissed anywhere
in the system [applause].
Thanks.
[ Applause ]
So what is this new presentation
style?
These presentations are called
Sheets, and Sheets aren't new at
all.
These presentations are just a
new design for the existing
UIModalPresentationStyle
pageSheet and its sibling,
formSheet.
Previously, these styles would
adapt to a full screen
presentation in a compact width
environment.
And now, they just stay Sheets
with their own special layout
and compact width different from
their regular width layout.
So, let's look at a few examples
of this in action.
In phones and portrait, you get
the appearance that you just
saw.
In phone in landscape, you get a
full screen layout like before.
But iPads aren't left out.
We've rethought Sheets here as
well.
Page Sheets float in a stack in
the middle of the screen, and if
multiple are presented on top of
each other, they'll form a stack
on top the review controller.
And specifically, this new size
follows the readable width, so
it's perfect for textual
content.
And because the readable width
changes with the user's
currently selected dynamic type
size, these page sheets can
change size as well, like this
or even like this.
Or they can take on a stacked
appearance if their preferred
width is wider than the
available width.
So, what do you all need to do
to get this new appearance in
your app?
Well very little because you've
done a lot of work to make this
transition as easy as possible.
The default UIViewController
ModalPresentationStyle has
changed to a new style called
Automatic.
Automatic is a dynamic
presentation style, which is
resolved at the time of
presentation.
To illustrate its behavior,
let's walk through a few
examples together.
So, here I have a custom view
controller, and it's going to
present UIImagePickerController
showing the user's photo
library.
And note that there's no modal
presentation style set.
This same code that worked on
iOS 12 and presented the image
picker full screen will now
present as a sheet with no code
change required on your part.
On the other hand, if I
configure the
UIImagePickerController to
present in camera mode, this
code will present the camera
full screen in iOS 13, just like
it did in iOS 12.
This is automatic at work,
resolving to different styles
depending on how a system
provided view controller is
configured so that you don't
have to make any code change.
Now, what about presenting our
own view controllers?
If I simply instantiate and
present a custom subclass of
UIViewController it will present
as a Sheet.
In other words, by default,
automatic resolves to pageSheet.
And this is great because it's
the right style for most
presentations.
Again, no code change required.
But, what about this last case?
If you have a custom view
controller that should be
presented full screen, such as
your own custom camera or other
immersive experience, you may
find that when you build this
code, your immersive experience
has been turned into a Sheet.
But don't worry, all you have to
do to fix it is explicitly set
the modalPresentationStyle of
this view controller to full
screen.
In general, it's good to leave
properties at their default
values and only specify an
explicit value when you're
intentionally deviating from the
default behavior.
And what about Popovers?
Well, Popovers always adapt to
sheets now.
So, if you want a Popover in
regular width and a Sheet in
compact width, all you have to
do is set your modal
presentation style to be a
Popover, and you're done.
You'll get exactly that
behavior.
Now, what do you all have to do
to support Pull to Dismiss?
In general, nothing.
If you present something as a
Sheet, the ability to pull it
down comes for free.
We will place a gesture
recognizer on your entire
presented view, so pulling down
in any noninteractive area will
trigger a pulldown on a Sheet.
And, if the user pulls down past
the top in any contained
scrollView, that will also pull
the sheet down as well
completely for free.
However, there are times when
pulling down a sheet maybe
undesirable.
For example, if we present this
same Sheet and enter some data,
the Sheet should not be allowed
to be pulled down, because it's
unclear if the user intends to
discard or save their changes,
and if the user does attempt to
pull down, the Sheet should
rubber band, and an action sheet
should be presented, showing
what actions the user can take
to escape this context.
So, to create this experience,
we have two new APIs.
The first is modal and
presentation, is a property on
UIViewController, and when you
set this to true on your
presented View Controller, it
will put the Sheet in a modal
state where it cannot be
dismissed,
and you'll get the
rubber-banding effect, just like
you saw.
This property supersedes the
existing isModal and Popover
property to prevent both Sheets
and Popovers from being
dismissed.
The second is a new
UIAdaptivePresentationController
DelegateMethod called
presentationControllerDidAttempt
ToDismiss.
So if you set the delegate on
the presentation controller
involved, UIKit will call this
method when the user pulls down
while in a modal state, at which
point you can present the action
sheet.
Here, you can see the
relationship between these APIs.
DidAttemptToDismiss is only
called if isModalInPpresentation
is true and the user pulls and
releases with the intent to
dismiss, so with some force or
velocity.
We call this the Modal Flow, and
we have a sample project that
shows exactly how to implement
an example like this.
See the link in the description
for how to download that.
But, we have more.
We also have a few more delegate
callbacks.
PresentationController
ShouldDismiss, which is useful
for preventing dismiss from the
delegate, WillDismiss, which is
a great place to grab one of the
view controller's transition
coordinators, which you can use
to set up alongside animations,
interaction change
notifications, and animation
completion blocks and
DidDismiss, which is great for
cleaning up state because it's
only called once if the user
actually pulls the Sheet down
and completes the transition.
These three callbacks supersede
similarly named UI Popover
presentationControllerDelegate
Callbacks because these APIs are
called for both Sheets and
Popovers.
Now, keep in mind that if a user
were to repeatedly tug on a
Sheet without pulling it down,
the delegate will receive,
Should and WillDismiss multiple
times before calling DidDismiss,
if it receives DidDismiss at
all.
Now, let's shift to Share
Extensions for a moment.
When you build with the iOS 13
SDK, your Share Extensions, just
like mail here, will become
Sheets, and Pull to Dismiss will
work here as well.
So, on the principle view
controller of your extension,
which is like the main view
controller you specify in the
Info P List, be sure to set
isModalInPresentation once the
user has started entering data,
and if you make your principle
view controller conform to
UIAdaptivePresentation
ControllerDelegate and implement
DidAttemptToDismiss, we will
call that method when the user
pulls down in this case, but
note that we will not call any
of the other delegate methods.
And this behavior will be
available in a future seed.
Moving right along, I have a few
things for you to consider.
The first has to do with
UIViewController Appearance
Callbacks.
Specifically, the difference
between the appearance callbacks
that the presenting view
controller receives during a
full screen presentation as
compared to a sheet
presentation.
During a full screen
presentation, the presenting
view controller's view is
removed from the view hierarchy,
and as a result, it receives
viewWillDisappear when the
presentation transition begins
and then viewDidDisappear when
the presentation transition
finishes.
And similarly, during the
dismissal transition when its
view moves back into the view
hierarchy, it receives viewWill
and DidAppear.
But, for Sheet Presentations,
the presenting view controller's
view is not removed from the
view hierarchy, and so it's
view, or the view controller
does not receive any of these
appearance callbacks.
So, if you have code in these
callbacks that you need to be
executed when a Sheet dismisses,
you should look at the
presentation controller Will and
DidDismiss methods that we just
talked about.
The second thing I want you all
to consider is that we have
inserted some private views in
the view hierarchy in between
UIWindow and its
rootViewController's view.
This change should not affect
you.
We just don't want you to be
surprised when you see these
views it the View Debugger.
The relationship between
UIWindow and it Root View
Controller's View is an
implementation detail of UIKit,
and because it is UIWindow's
responsibility to manage and add
this view to the view hierarchy.
In general, the structure of a
view hierarchy not owned by your
app is liable to change without
notice in any release.
So, always ensure that you're
writing your code in a way that
doesn't make assumptions about
private view hierarchies.
So, use Sheet presentations in
your apps.
They're meant to be used for
most UI with few exceptions, and
implement the modal flow when
pulling down requires the user's
intent.
And remember, there's a sample
project that illustrates exactly
how to do that in more detail in
the session's description.
Thanks everyone, and now I'm
going to hand it off to Kyle to
tell you more about Search.
[ Applause ]
>> Good job.
Thank you, Russell.
Hello everybody.
My name is Kyle.
I work on UIKit, and I'm going
to tell you some new things in
iOS 13 about Search.
Now this isn't new.
This is the existing interface
for searching in the mail
application, and it is provided
by UIKit.
Specifically, the
UISearchController subclass of
UIViewController.
It's familiar to all of our
users, and it's available in
your applications too, and it
consists of a number of parts.
The biggest piece is a
UISearchBar, which you can see
here at the top of the screen.
The search bar has a couple of
components including a Cancel
button and what we call the
Scope Bar, which is that row of
buttons underneath the search
field.
Now, you may notice the updated
visual appearance of the Scope
Bar in iOS 13, but now we're
allowing our application to hide
elements of the Search Bar even
if it's managed by a
UISearchController.
So, if your application doesn't
need a Scope Bar or a Cancel
Button but wants to make them
available perhaps depending on
the UI state.
You can control that directly
with new properties on
UISearchController.
Also, we're exposing the
SearchTextField as a public
property on UISearchBar, which
means that it's really easy to
customize.
[ Applause ]
So to customize the appearance
of your SearchController, set
these properties to false on
UISearchController and use the
existing properties on
UISearchBar to control the
visibility of the Cancel Button
and the Scope Bar.
Use the searchTextField Property
to get a reference to the
UISearchTextField instance and
change all the properties on the
Text Field that you'd like to
change.
It's a subclass of UITextField
and all of the styling
properties are available there.
UISearchController's behavior
extends to the appearance and
dismissal of Search as well, so
the standard behavior is that
when you activate the Search Bar
by tapping on its Search Field,
it gets hoisted to the top of
the screen, but the content that
was visible on the screen before
remains visible.
As you type, in this case the
photos application displays
results that match your partial
search term, and this is
implemented with a
UIViewController that your
application provides called the
Search Results Controller.
Not every application behaves
this way.
For example, the mail
application, as soon as you tap
on the Search Field provides a
list of suggested searches.
This is still a
UISearchController's Search
Results Controller, and we're
making this functionality
available to you in iOS 13 as
well.
[ Applause ]
Just set the
showsSearchResultsController
property on your Search
Controller to true, and you can
manage the automatic behavior
with automatically shows search
results controller property.
There's another big feature in
Search.
In Mail and Photos and other
applications on the system,
these suggested searches result
in what we call a token, which
is a visual representation of a
more complicated search query.
This functionality is available
in your application on any
instance of UISearchTextField
via the new UISearchTokenAPI.
And these tokens support Copy
and Paste and Drag and Drop.
It's the same implementation
that we use for all of our
applications.
[ Applause ]
For example, Photos uses it to
provide saved or predicted
searches for people, places, and
objects.
Tap on any of the entries in the
SearchResultsController, and
Photos transforms even a partial
input into a token.
As this is a subclass of
UITextField, the tokens do
interact with the text.
In fact, they're always prior to
the text.
For example, if I pace the token
into the search field, even
though my insertion point is at
the end of the search field, the
token appears at the beginning,
and as you can see here, the
token is now selected.
And I can extend the selection
to include both the token and
some text.
Creating tokens is pretty easy.
First, grab the selected text
range to figure out what text
you want to convert into a
token.
Create a UISearchToken object,
and call this method on the
SearchTextField to replace the
textual portion of that range
with a token.
Your app is in complete control
over the insertion and removal
of tokens, so you can attach any
meaning to them that you want.
Now, UITextField conforms to a
protocol called UITextInput.
If you're doing programmatic
selection, it's important to
understand some aspects of
UITextInput, namely ranges and
positions.
In a normal text field, every
character is assigned a
UITextPosition, and these
positions are relative to two
well-known positions at the
beginning and the end of what we
call the document, which is the
search field's content.
And you can use these positions
to create UITextRanges.
For example, to programmatically
select a portion of the field's
content.
Because tokens are selectable,
they too get UITextPositions.
But the length of the text of a
search field is now different
from the distance from the
beginning of the document to the
last character's position.
If this matters to you, for
example, to programmatically
select a portion of the text,
UISearchTextField exports this
new property, textualRange.
The beginning of the
textualRange is the first
nontoken character in the field,
and its end is the end of the
document.
These match up with character
indexes in the text property.
So, to take advantage of all of
this new functionality in your
application, take a look at the
new properties and customization
options available on
UISearchController.
Use UISearchTextField either
inside the UISearchBar or
anywhere else you can use a
UITextField today, and customize
it with all of the customization
options that are available on
UITextField.
Adopt UISearchToken to represent
complicated queries in a concise
editable fashion that supports
Copy and Paste and Drag and
Drop.
There's a lot of advanced
techniques you can do with this,
so we're going to have a sample
project available soon at this
session's website, that
demonstrates how to use tokens
effectively.
Now, I'm going to hand it over
to James, who's going to talk
about Gestures.
[ Applause ]
>> Thanks Kyle.
Hey everybody.
I'm James McGaran, and I'm here
to show you some new Gestures
that we've added in iOS 13
themed around selection,
organization, and some common
editing shortcuts.
So this is everything I'm going
to be talking about today.
The best news you're going to
hear all day is that a lot of
this behavior is actually
automatic, stuff that you're
going to get for free, but I'm
here to tell you about what's
different and what you need to
do in order to take full
advantage of these new features
inside of your application.
So, let's start with some new
features regarding text
selection gestures in custom
text views.
So, as you know, there's a lot
of really great existing ways to
select text on iOS using
Gestures.
You can tap and hold to start
highlighting right away, that's
a new thing in iOS 13.
You can long press to get the
selection loop and move the
insertion point around, and you
can triple tap on a paragraph to
select the entire paragraph all
at once.
So, these Gestures work great in
native text widgets like
UITextView and UITextField.
You already get those.
But, there might be some cases
where you need to go beyond what
TextView and TextField are
capable of.
Some of you need to implement
highly customized text drawing
in your apps.
So, here's books as an example,
where they use a completely
customed text view to control
the margins, character spacing,
etc. So, currently, in order to
get selection behavior like this
in a custom text view, you had
to manually add all of the
system text selection Gestures
to your app just to get parity
with the native text widgets.
Many of you also had to
implement you own UI for
selection, like the selection
rectangles, the blue selection
rectangles or the selection
handles just to offer this
behavior.
So, I'm pleased to announce in
iOS 13 this can be accomplished
much easier with a new type of
UIInteraction called
UITextInteraction.
So, in case you're not familiar
with UIInteractions, you can
think of them as a way to
encapsulate sort of a set of
behaviors and Gestures related
to UIKit widgets.
Think of Drag and Drop
interactions, similar to that.
So it's only three lines of code
to add all of the system test
selection Gestures to your app,
the ones that your users are
already familiar with.
We provide a set of Gestures for
editable and noneditable text
interactions, and you can use
the UITextInputProtocol to get
more fine grain control over the
selection UI, like the
rectangles and the handles that
I was mentioning before.
So here's what you need to do to
get started with
UITextInteraction in your Custom
Text View.
So, as I said, it's only three
lines of code to do this, minus
the comments.
So you create the interaction
using UITextInteraction 4, and
let us know if you want the set
of Gestures for editable or
noneditable text fields.
Then assign the text input
property to your view that
implements the
UITextInputProtocol.
We keep this separate in case
you want Gestures to work on a
container view, like a scroll
view, but you want all of the
text selection behavior to get
handled by some contained view,
like the one that's actually
drawing the text.
And finally, just add the
interaction to your view with
Add Interaction.
Well, take a trip--
[ Applause ]
Take a trip with me over to this
side of the stage, and we'll
talk about multiple selection
Gestures in TableViews and
CollectionViews.
So we've long supported Multiple
Selection Mode in
UICollectionView and
UITableView.
Apps like Notes here have a
Select button on the top right
corner where users can tap it to
enter multiple selection mode
and then individually select
each individual note one by one
to group them together and then
organize them with Drag and Drop
or one of those action buttons
at the bottom there.
Well, I'm pleased to announce in
iOS 13 we're introducing a
totally new way of quickly
selecting a contiguous batch of
items in collection views and
table views.
So, let me show you what that
looks like here on this giant
iPad.
So now, users will be able to
instantly jump into multiple
selection mode by simply placing
two fingers down anywhere on a
table or collection view and pan
across to start selecting right
away.
Thanks, that's really awesome.
So, here you can see taking two
fingers and sliding down the
list view in files will
instantly put it into edit mode
and start selecting cells.
Even cooler, the same works for
a grid of items in a
UICollectionView flow layout, so
your users will be able to pan
two fingers across a grid of
items and select a bunch of
things all at once.
This is absolutely a dream come
true for Drag and Drop.
Not to mention, if your users
have a hardware keyboard
attached, they can also hold the
shift or command key to tap on
other items, and it behaves just
like it does on macOS.
Thanks.
[ Applause ]
And now especially that your
iPad apps can run on the Mac,
your table views can feel right
at home.
So, these awesome new behaviors
are currently opt in, and the
reason why is because your app
might need to adapt around the
fact that your user intends to
enter multiple selection mode.
For instance, you might want to
change the select or edit button
to say cancel or done instead.
You might want to show action
buttons at the bottom of the
screen for stuff to do with the
things that your user selected,
or you might to disable some UI
like the add not button in this
case.
So, to account for this, we're
adding just a couple of new APIs
to help you adapt to these new
behaviors.
It's really easy.
There's only two delegate
methods to implement, and
there's roughly equivalent
versions on both Table View and
Collection View.
So here they are.
The first one to implement is
just Should Begin Multiple
Selection Interaction at Index
Path.
Or you can return true if you
would like to allow the gesture
to begin.
And we give you the index path
here in case you'd like to
prevent the selection from
beginning on a part of your
table view that's not
selectable, in which case you
can just return false.
And the second method to
implement is did begin multiple
selection interaction at index
path, where you can adapt your
surrounding UI to account for
the fact that the TableView was
automatically put into Multiple
Selection Mode, just like we're
talking about on the previous
slide.
So moving on, the last thing I
want to talk about is just
briefly cover some enhancements
that we've made to some common
editing tasks using some new
gestures.
So, in iOS 13, we're introducing
a standard set of Gestures to
make it easier to do some common
editing tasks.
For example, using three
fingers, users can now swipe
back to undo and then swipe the
other way to redo.
Pinching three fingers in will
copy, and then pinching them out
will paste.
So, we're bringing this standard
set of productivity gestures to
the system so that you don't
have to worry about implementing
UI for these common editing
commands.
It's unified across the whole
system so your customers will be
able to discover right away
within your app, and they'll be
instantly familiar with it.
It's really great for drawing
apps because you don't need to
show any floating panels or
Toolbars in order to offer this
behavior.
And best of all, it's completely
free if you're already using
undo manager or NS undo manager.
So, my call to action here is
for you to try these gestures in
your app when you get a chance
and make sure that they work
really well.
But just in case, I can see some
of you are nervous, so just in
case they conflict with other
three-finger gestures that you
might have within your app,
we're offering an escape hatch
via some new API.
It's just a simple property that
you override on UIResponder
called
EditingInteractionConfiguration,
where you can return none if
you'd like to opt out of these
gestures.
So here's the takeaway, I hope,
for today.
Finally offer system-wide
standard text selection gestures
in your customized text widgets.
Change the way your users
organize information in your app
using multiple selection
gestures.
I really hope you adopt that
one.
And finally, allow your users to
stop shaking their iPad and
control the undo stack with a
standard set of gestures.
[ Applause ]
Yeah, it hurts.
So, thanks.
Now I'd like to hand it off to
Mohammed to talk about menus.
[ Applause ]
>> All right.
Thanks James.
Hi everyone.
I'm Mohammed, and I'm excited to
talk to you about some powerful
new APIs we're introducing in
iOS 13 that allow you to present
fluid interactive menus with
rich previews in your apps.
The first of these APIs is
UIContextMenuInteraction.
UIContextMenuInteraction is a
UIInteraction that lets you
present menus with rich previews
and complex hierarchies.
These hierarchies can have
nested sub-menus and in-line
sections.
We'll see what that means later
on.
The menu presented by the center
action is highly adaptive,
meaning it'll do the right thing
depending on the context in
which it's presented.
So, here we see it on an iPhone
in portrait.
We have the preview and the
actions kind of vertically
stacked above one another.
On an iPhone in landscape, we
get the preview and the action
side by side to better take
advantage of the available
space.
And on an iPad, it reconfigures
itself depending on the
available space and size of its
preview and actions list.
And since this is a
cross-platform API, if you're
running your app on the Mac, it
turns into a familiar macOS
context menu.
The interaction provides a
consistent experience by
presenting the menu using the
same gesture throughout iOS.
So users will come to expect
that this gesture brings up a
menu anywhere in the system.
The gesture will adapt to the
device's capabilities.
So, on phones with 3D touch, we
will use 3D touch to bring up
the menu quickly and provide
some nice feedback.
On phones without 3D touch
capability, we'll use Haptic
Touch, and we'll keep that nice
feedback whenever the menu pops
up.
On other iOS devices, we'll use
a long press, and on the Mac,
it'll be your user's secondary
click setting.
So, a right click or a command
click or two-finger tap.
The interaction is automatically
integrated with other system
behaviors like Drag and Drop.
So if you've adopted
UIDragInteraction in your app
and you choose to adopt
UIContextMenuInteraction
alongside it, users will be able
to transition into dragging at
any point.
So, here we see as soon as that
initial threshold for dragging
is met, you're able to move your
finger to drag the photo over to
the files app.
However, if you wait a little
bit longer under the menu is
presented, you're still able to
transition smoothly into a drag
without removing your finger
from the screen.
So users have this nice fluid
continuous experience.
The second part of our API
package today is UIMenu and
UIAction.
UIMenu and UIAction are a
hierarchical menu construction
system that allows us to define
and describe the menu
hierarchies that we're going to
want to display.
UIMenus are composable.
They're basically like building
blocks that we can put together
in different configurations to
describe different menu
hierarchies.
So, in a simple example here,
I've created a two action menu
by creating a UIMenu and passing
it to UIAction children, a share
action and a delete action.
If I want to add a little bit
more functionality to my menu by
say adding a sub-menu, all I
need to do is create another
UIMenu, give it some descriptive
title to display at the previous
level in the hierarchy, and pass
it the desired children.
So here I've chose to include a
copy and a duplicate action.
So, when we present it, the menu
looks something like this.
We have a Share action at the
top, our edit action for our
sub-menu in the middle, and a
delete action at the bottom.
When the user taps edit, our
sub-menu is presented, and our
copy and duplicate actions pop
in.
Adopting the interaction in your
app is pretty straightforward.
If you've adopted other
UIInteractions in your app like
UIDragInteraction or some of the
TextInteractions that are being
introduced this year, this
pattern should be really
familiar to you.
The first thing well need to do
is just create a
UIContextMenuInteraction with
some object as its delegate.
So, this could be our View
Controller, for example.
Then we'll need to attach it to
some view using UIView's
addInteraction method.
Once we've done that, we'll need
to conform to the interaction's
delegate protocol.
The protocol has a single
required method that is called
when the interaction is about to
begin.
It's the app's job at this point
to either return a configuration
to start the interaction or
return nil to indicate that
there's no menu to be presented
for the current location.
The configuration object is how
we're going to describe our
menu.
It has an identifier.
The identifier is optional.
It's for you to use to be able
to identify the interaction
throughout its lifecycle,
throughout the various delegate
callbacks that you might get.
It also has a previewProvider
and action provider closure.
Both of these are called when
the menu is about to be
presented.
This allows us to defer the
potentially expensive work of
actually building up the menu
and the preview until they're
actually needed.
So, in the example that we just
looked at, our menu doesn't have
that large rich preview.
It just has some actions, so
we're going to focus on creating
an actionProvider in our
implementation of the delegate
method.
So the actionProvider, when
called, has a list of suggested
actions that are passed to it by
the system.
This can be a mix of UIMenus and
UIActions, so potentially a
fully constructed hierarchy that
are picked up from the system.
These could be things that you
defined in your responder chain
using the new UI command API
being introduced in iOS 13 or
things that are offered by other
system components.
So we're doing a fully custom
menu here, so we're going to put
the suggested actions aside.
First, we'll create our edit
menu.
We'll just create a UIMenu with
the title Edit, and we'll pass
the two children that want it to
have, a UIAction, with the title
Copy, and a UIAction with the
title Duplicate.
Then we'll define our root menu.
It often doesn't make sense for
a root menu to have a title, so
we'll skip it here.
However, if you do want to pass
it a title, it'll be displayed
as a header above the actions
list.
And we'll pass it three children
here, a share action, the edit
menu that we just created, and
finally a delete action with a
destructive style to indicate to
our users that the action has
destructive consequences.
Finally, we'll create a
configuration with some
identifier and pass it our
action provider.
And that's it.
That's really all it takes to
create and display menus using
UIContextMenuInteraction.
But with a little bit more work,
we can take advantage of some of
the animation customization APIs
offered by the interaction
delegate to build some really
great, highly polished
animations that really
communicate meaning to our
users.
So, in this example here, I've
taken the same menu that we had
earlier, and I've used the
source presentation
customization API to make the
menu appear from the cell's icon
instead of from the entire cell,
and I've even customized the
background color and even given
the preview a nice circular
shape.
These customization APIs are
built on a UITargetedPreview.
This is a new API that's being
introduced in iOS 13.
Now, if you've adopted
UIDragInteraction and
UIDropInteraction, and you built
some custom Drag or Drop
Previews in your app, then this
is probably very familiar.
We've essentially taken
UITargetedDragPreview and
generalized it into a more
general API that can be used by
other interactions.
UITargetedDragPreview is now a
subclass of UITargetedPreview.
So, if you already have
meaningful drag previews that
make sense for your menus
because they're triggered from
the same item, then you can
reuse that code without doing
any extra work.
To make adopting this in your
apps even easier, to make it
easier for you to bring up menus
in some of the most common
cases, we're also introducing
some convenience API for
UICollectionView and
UITableView.
All that's needed to bring up a
menu from your app, from your
Table View on all the platforms
that your app runs on is to
implement a single extra method
on its delegate.
Here, you'll once again return a
configuration if you have a menu
to display or return nil to
indicate that there's nothing to
be shown.
So, out of the box, these
convenience APIs give you some
polished default animations with
menus presenting from Table or
Collection View cells and then
returning back to them when
dismissed.
We're also providing the same
custom presentation and
dismissal hooks so you could
build your custom appearance and
disappearance animations.
Now, you're probably thinking to
yourself, this sounds a lot like
Peek and Pop in some ways.
Well, we noticed that too.
However, since this new API
provides a much larger feature
set and works on multiple
platforms, we are deprecating
UIViewController previewing in
iOS 13.
So, go and replace your
implementation of Peek and Pop
with UIContextMenuInteraction
and give your users a consistent
experience in your app across
all devices.
You might also want to consider
replacing any long-press driven
menus in your apps with this new
interaction to take advantage of
the new feature set.
And if you have menus that
you're currently displaying
alongside Drag and Drop, this is
a great fluid solution that has
coordinated gestures and a fully
integrated experience that your
users are going to come to
expect starting in iOS 13.
All right, so now that you're
equipped with all this great new
knowledge, you should go and get
your apps ready for iOS 13.
Ensure that they're ready for
the future by making them
flexible, take advantage of the
new bar appearance and
presentation APIs to give your
apps that polished modern look
that users are going to come to
expect.
Go build the search experience
you've always wanted to build
using the great new search APIs,
and give your apps some great
features with the new
productivity gestures and
context menus.
If you have any questions about
these topics or anything else
related to UIKit, please come to
the labs tomorrow, and for
additional information about the
session, you can find it at the
session's website.
Thanks for coming by, and I hope
you enjoy the rest of the
conference.
[ Applause ]