SwiftUI On All Devices

Session 240 WWDC 2019

Once you’ve learned the basics of SwiftUI, you’ve learned what you need to know to use SwiftUI anywhere. You can use the same SwiftUI skills for making an iOS app as you would for making an app on watchOS, tvOS or macOS. We'll cover the basics, and then dig into more detail about how SwiftUI can help you make changes to your app on every Apple device. Hear about design principles for each platform and learn about how much code you can share across platforms. See how to incorporate device-specific features and how to make changes in SwiftUI by following along with a starter project, available for download.

[Music]

[Applause] All right, thank you.

Welcome. It's so great to see you all here and it's great to see so many people excited about SwiftUI.

My name is Jeff Nadeau.

I work on macOS frameworks and I'll be joined in a little bit by my colleagues Ada Turner and Meghna Sapre [phonetic].

Now we hope you've had the chance to learn about SwiftUI all throughout the week but if you need a summary, here it is.

SwiftUI is the shortest path to building great apps on every device.

And what we're here to focus on today is the 'every' in every device.

Now when we think about building applications for all of our Apple devices, these are the technologies that we think about.

We use AppKit on the Mac.

UIKit on iPhone and iPad, TVUIKit which is built on UIKit for Apple TV, and then on the watch we use WatchKit.

These UI frameworks were designed around the strengths and capabilities of the respective devices.

And so naturally there are some differences between them.

And historically we haven't been able to take code written for one and move it over to another device without modification.

But for the first time ever, we're introducing a UI framework that you can use on any of these devices.

That's unprecedented and it's a big opportunity for you as app developers.

But these devices are so different so how is it that we've built one UI framework that works on all of them?

Well, SwiftUI was built from the ground up to accommodate many different UI paradigms.

So whether you're using a keyboard and mouse, or a multi touch display, or the Siri remote, or even the digital crown on your Apple Watch, or assistive technologies like voiceover and switch control, SwiftUI was designed to accommodate all of these.

And it has great support for our platform design conventions out of the box.

We've brought together experts from every platform to make sure that when you use an element in SwiftUI on a given device that it looks and feels right at home.

The result is a system where your knowledge is transferrable across devices.

Everything fits together in the same way.

So even when you're working with you're building support for some specific piece of hardware, say the Touch Bar on a MacBook Pro or the digital crown on an Apple Watch, or the Siri remote, the tools for doing this have a kind of consistency and familiarity that makes them really easy to pick up.

Now, on top of just general design philosophy we also have a number of elements that are in common across SwiftUI across all devices.

So for example, every platform has the idea of a toggle control.

You've got some kind of piece of Boolean state that you want to be able to toggle and you have a label describing what you're toggling.

And so even though our expression of this control could be very different on each device it might be a switch or a check box or a toggle button we can offer a single API that describes this on any device.

SwiftUI also has a common layout system.

So when you're using a stack or a spacer or a padding, these tools work the same on every device.

And what that means is that once you've learned to lay out an application on one device, you've learned how to lay out an application on any.

We also have some more advanced controls like picker for example.

Picker picks one element from a list of many and this control expresses itself in a variety of ways.

So on MacOS it might be a pop-up button.

On iOS or WatchOS it might be this wheel style picker.

And given how different they are, you might not use them completely interchangeably from device to device.

But the one thing that's constant is the relationship to your data.

When you've adapted your model to work with one of these controls, you can easily transplant that from device to device.

Now we don't have time to go over all of the different elements available in SwiftUI so you should check out the SwiftUI essentials talk for more information about that.

Now, does that mean that I can really use SwiftUI to design a single app that's going to work great across all these devices?

Is it going to let me write code to adapt seamlessly from a 4k television all the way down to a 44 millimeter watch face?

Well of course not.

You know, there's no such thing as a one size fits all app.

If we decided to just stick to the common denominator between all these devices, we'd be missing out on the things that make each device great.

And there's no magic abstraction that can do that for you.

You have to decide what the right design is for your app on each device.

Now what SwiftUI can help you with is you can share your skill set and toolset that you've learned building from one device across many others.

And there are definitely going to be opportunities to share code along the way, just where it makes sense.

And so we think it's kind of important to think about this less as write once and run anywhere and more like learn once and apply anywhere.

Now to put these principles into practice, we need to build an app.

But really it's more like we've built four apps, one for each of our platforms.

And the app that we've built is called Landmarks.

The purpose of Landmarks is to research and visit landmarks throughout the country.

We definitely want to look at photos and get visitor information about these places.

I think it would be great to get maps and directions to a destination.

And if we're planning a trip, marking favorites is a great idea.

And when we think about bringing this app to all of our devices, we can tell ourselves a story about how we think the app belongs and fits on each one.

So for example, on AppleTV it's a natural place to couch surf for places to go.

And because it's a big screen experience, that might be something that you do with family or friends or roommates.

And we definitely want to mark favorites to research later.

And the Mac would be a great place to do that research.

It's a good place to compare and contrast info, maybe have some more advanced sorting and filtering controls, and really read up on all the details.

On iPhone, we obviously want quick information about each landmark but since it's so common to navigate with our phones, we should also be able to get driving directions as well.

And iPhone of course is also a phone so if we need to place a phone call to call ahead, it's a natural place to do it.

Finally on Apple Watch, that's where we want to get at-a-glance info about what's most important to us.

And it's the perfect platform to receive important notifications when anything changes.

Now the cool thing is that the iOS version of this application is already available to you today.

It's part of a new documentation series to teach you how to view SwiftUI.

You start from the very beginning and you can build this application up step by step.

It's already available for download today and it's a great way to learn how to build an iOS app.

And so as a result, we're going to be focusing more today on bringing this application to AppleTV, Mac, and Apple Watch.

And to start us off on that journey, I'd like to hand it over to my colleague Ada Turner to talk to us about SwiftUI on AppleTV.

[ Applause ]

Thanks Jeff.

Hi. My name is Ada Turner and I'm really excited to talk to you today about SwiftUI for AppleTV.

Designing apps for the TV means designing for the biggest, boldest screen in the entire home and that comes with some challenges and considerations unique to AppleTV.

Luckily, SwiftUI allows you to create great experiences that are optimized for the living room using the same skill set and toolset that you've learned when developing for Apple's other devices.

Today I'd like to focus on three key points for designing great experience on the biggest, boldest screen.

TVOS is a 10 foot experience, not a mobile experience.

People interact with your apps using the Siri remote not a touch screen or a mouse and keyboard.

And it is especially important for TVOS apps to have streamlined navigation so people can jump right into your app's content.

Now, what is a 10 foot experience?

It's this, not this.

Your apps should emphasize rich and immersive experiences like beautiful imagery or video as opposed to accomplishing tasks like taking notes or getting directions.

When sharing SwiftUI code with your AppleTV app from other devices, carefully consider which experiences make the most sense when displayed on a large screen viewed from across the room with longer periods of use and potentially more than one viewer at a time.

Let's take a look at which features we decided to support on Landmarks for TV and which ones we left on the cutting room floor.

The easiest choice to make was to include the gorgeous photographs of the landmarks which will look great on the big screen.

Gathering in the living room to pick out favorites together is one of the key features of our TVOS app so we can't forget that.

And we'll also include basic tourism information such as hours of information and cost so that people can make informed decisions about where they want to visit as they browse.

Now, although our data supports it, we decided that we're not going to include lengthy details about the history of each landmark as content like that really isn't appropriate on the TV.

We also decided not to include advanced sorting and filtering as features like that make a lot more sense on the Mac or iPad.

And finally, although our data includes geographical coordinates, we decided not to implement geofenced notifications as traveling with an actively running TVOS app is a very rare use case.

[Laughter]

Next, let's talk about focus.

People interact with TVOS apps using the Siri remote which is optimized for effortlessly swiping through your app's interface.

It is critical that your entire apps interface be intuitively navigable using focus.

Luckily, many of SwiftUI's standard interface elements such as lists, buttons, text fields, and toggles, all work seamlessly on TVOS, adopting different appearances and behaviors that look great on the big screen and interact using focus.

If you implement your own custom controls, SwiftUI provides a focusable view modifier that allows you to control whether or not your view can become focused and execute a block of code when your view gains or loses focus.

You can also use the on play pause command and on exit command view modifiers to respond to people pressing the play pause and menu buttons on the Siri remote when your view is focused.

Thank you.

[ Applause ]

Finally, let's dive into some best navigation practices on TVOS.

Long, vertically scrolling tables of content with deeply nested levels of navigation work great on the Mac or iPhone, but on TVOS people want an effortless browsing experience that emphasizes content.

Using SwiftUI's easily composable stack views, list views, and scroll views, we can create an interface like this on Landmarks for a TV with vertical stacks of horizontally scrolling shelves that really take advantage of the widescreen display on the TV and allow people to browse between different categories without having to navigate between different pages.

First, let's take a look at how we might structure the top level navigation of a SwiftUI app for AppleTV.

Tab view is the primary means of navigation for many TVOS apps.

It allows you to break your app's content up into distinct categories that are easy to switch between and provides a persistent indicator at the top of each view that lets people know where they are in your app.

Navigation view allows you to nest pages of content and optionally display a navigation bar with a title or buttons.

I'd like to make a quick note on structuring your app's top level navigation on TVOS versus iOS.

On iOS if you use a tabbed view, it will typically be the top level view of your app and each of its child views may be a navigation view with your app's content as the navigation view's root view.

With this structure, when people navigate deeper into your app's content, the tab bar will remain visible allowing people to easily switch tabs at any time.

Here on photos the tab bar remains visible on the bottom of the screen after navigating to the details page so that people can easily switch tabs without having to navigate backwards.

However, on TVOS if you use a tab view you will actually want to make the navigation view the top level view of your app and set its root view to the tab view with your app's content as the direct children of the tab view.

With this structure, when people navigate deeper into your app's content, the top bar will disappear and we want this behavior because TVOS is all about full screen experiences that emphasize your app's content.

Here on photos for TV the tab bar disappears when we navigate deeper into the album's details so that people can focus on the contents of the album.

SwiftUI views are highly composable so it's super easy to rearrange your app's navigation structure for TVOS.

The nested relationships between the tab view, navigation views, and content views, are all visually indicated by the inherent structure of your code.

Now, let's put some of these principles into practice and tune up landmarks for TV.

First we will no longer be needing this navigation bar button title.

Next we'll get rid of this navigation button and data header label.

Let's see how this looks.

This is definitely an improvement but we've got a ways to go.

This long, vertically scrolling list doesn't quite feel right on TVOS so let's use a scroll view with a nested HStack instead of a list.

And let's display all of the landmarks within a category inside of a row.

Let's take a closer look at the row.

It's very similar to category landmarks with the addition of a VStack containing a header label and an HStack wrapping the four each landmarks.

One thing to note here is that instead of a plain text view, I'm using a custom view called landmark card as the label for the navigation button and I'm sharing this view directly with the iOS app.

Let's give this a run.

This is starting to feel a lot better.

By changing only a few lines of code, I now have a nice, big inviting buttons with images and a vertically scrolling list that really takes advantage of the wide screen.

One thing I'd like to point out here is that while we're still using the exact same navigation button view in landmarks row, its appearance has changed.

The chevron on the right hand side of the view is gone and the background is different.

This is because navigation button is no longer being displayed in the list view and has automatically adapted its appearance.

Now, while the horizontally scrolling content looks great on the big screen, it might be a little too horizontal.

Let's vertically stack the categories by changing the main view's HStack to a VStack.

And adding a nested scroll view around the row's HStack.

Let's give this a run.

Ah, this is feeling really, really great.

It's super easy to browse between different categories and browse the landmarks within each category.

Finally, let's take a look at the details page.

Well, this beautiful edge to edge photograph of the landmark would be looking pretty nice if it wasn't obscured by all of this high density text.

Let's see what we can do to make improvements for AppleTV.

So let's take a look at the details view.

It's a pretty simple view.

We have a background displaying a photo of the landmark, a favorites button, and some historic details.

Let's try displaying tourism details.

Try one last time.

Ah, that's looking so much better.

Only the most relevant details are being displayed with nice large fonts that are easy to read from across the room.

We can mark a few landmarks as favorited for when we do more detailed research on landmarks for MacOS.

Now, back to you Jeff.

[Applause]

Thanks Ada.

I love that Ada was able to take a pretty standard list-based UI and really make it feel at home on AppleTV just by rearranging a couple of pieces that she already had.

I think that really shows how powerful this framework is.

So now let's turn our attention to MacOS.

Now there's a lot that goes into making a great Mac app and I could probably fill the whole hour if we had it, but I'm going to focus on a few key points that SwiftUI can really help you with high information density, multi windowing support, keyboard shortcuts, and support for the MacBook Pro Touch Bar.

Let's start with high information density.

We generally have a lot of screen real estate to work with on the Mac and so we can use that to provide more information at a glance.

That can make it easier to make more, to make better decisions and make comparisons if you have all that information all in one place.

And because we have a precision pointing device on the Mac, we can tolerate smaller click targets and denser controls.

Now that doesn't mean that your app should look like an airplane cockpit, but it does mean that you can provide more functionality in one place and leave more room for your content.

And the Mac is a great place to read lots of text content if you have text content.

So app sessions are often longer on the Mac and you're usually using it seated so it's very comfortable to just scroll through some text and read it.

Now SwiftUI automatically adjusts the spacing and paddings between elements to be appropriate for the Mac.

And you can use the control size modifier to access the small and mini sized controls that we have available on the MacOS system.

And that might be great if you want to make an entire inspector use small controls.

Next multi windowing.

You know multiple windows have been just a staple of the MacUI for decades, and people love using multiple windows.

They love using multiple windows to compare content across windows side by side.

It's often nice to pull a single item out into its own window so you can focus on it in detail.

And many people love organizing their windows spatially across their desktop and spaces.

And these are all capabilities that you unlock if you support multi windowing.

And SwiftUI makes this super easy.

I'll show you an example of that in a little bit.

Next, keyboard shortcuts.

Keyboard shortcuts are an essential part of a MacUI.

Mac users and especially power users love using keyboard shortcuts to access common actions and just fly through your app's navigation.

And supporting keyboard shortcuts in SwiftUI is really easy and I'm going to show you an example.

So let's say we have a tab view.

We've got three tabs for explore, hikes, and tours, and what we want to do is bind each of these tabs to command one, two, and three, so that we can switch between them really quickly.

Now when we want to set up a keyboard shortcut on the Mac, the first place that we go is actually the Mac menu bar.

We like to put keyboard shortcuts into the Mac menu bar because it makes them more discoverable and it ensures that whatever actions we're hooking up here are also accessible if you're using just a mouse.

Now you could do this in code.

I've gone ahead and set it up in my storyboard.

And then what I've done is defined some commands for each of these keyboard shortcuts.

A command is just a name for a command that can be sent through the SwiftUI hierarchy and we can use them to wrap the selectors sent by each of these menu items.

Putting it all together, all we have to do is use the on command modifier attached to the view that we want to recognize commands on.

In this case we pass in the command that we just defined a moment ago, as what was a block of code to run when the command occurs.

Here we're just setting the selected tab variable that our tab view is already bound to.

So when we use one of these commands, the selected tab variable updates, the tab view notices and updates itself as well.

If you want to know more about recognizing keyboard shortcuts and other system level integrations like this you should check out the integrating SwiftUI talk from this year.

Finally, the Touch Bar.

The Touch Bar is another great way to accelerate common actions on your Mac.

It brings the most common and contextual actions right at your fingertips.

And supporting the Touch Bar in SwiftUI is easier than ever.

I'll show you an example.

We define a Touch Bar in code and then just like we're populating a list or a stack, we just put the elements that we want in the Touch Bar one by one.

And when we want to attach this to a view, we'll just use the dot Touch Bar modifier, passing in the Touch Bar that we're just defined.

And it's that easy.

Whenever this view is the focused view or the nearest ancestor of the focused view, these controls will appear in the Touch Bar hardware.

Now let's go back to our demo so we can put some of these into practice for Landmarks for MacOS.

Okay here we are in Xcode.

Let's just build and run Landmarks for MacOS so we can see where we're starting.

Okay, we have a fairly standard master detail view here where we've got a list of landmarks on the left and the details on the right.

We've also added some filtering controls so that we can go filter down by category or we can choose to see only our favorites.

Now the really neat thing is that this list I've got here on the left side is actually something that I shared completely with iOS.

And that was great.

It gave me a really big head start to making this app.

And I didn't have to do any adaptation.

I didn't have to adapt it to a new data source or delegate protocol or anything like that.

I just got it for free.

But I do think that this list could look better on the Mac.

I wish I could see more elements in my scroll view at once and I'd love to have more details in each row.

Let's start by taking a look at how this is defined.

In our landmark list we've gone ahead and actually defined a Mac landmark list that wraps this landmark list which is a common element that I discussed earlier.

Structuring our project like this is really handy because it means that I can still mostly share the implementation of this list but it gives me a place to put my Mac specific customizations.

Let's follow this to look at how this is defined.

We have some filter criteria that just describes the configuration of our filter controls that we looked at earlier.

We have a binding to the selected landmarks the list so that the list can show and modify it.

And we have some user data so that we know what landmarks are favorited.

And the list is pretty simple.

You've probably seen this a number of times already.

We have a list we use for each to iterate over all of our landmarks to display.

And then we create a landmark row for each one.

And this is a hard-coded type here.

It's just, this is the type of row that we're using right now.

Now we could start doing something like poundif [assumed spelling] to exchange what landmark where we're using on each OS but I really don't want to do this as a hack.

I want to build a tool that I can reuse.

And so let me show you how I'm going to do that.

So I'm going to redefine this list to be generic over the type of landmark row that we're going to use.

And then I'm going to add a property which is a closure from the landmark to the row type that we've just defined as a generic type.

And then instead of using a hard-coded type here I'm going to delegate the creation of the row to my block.

Now, to adapt that in my Mac landmark list, all I have to do is update my type definition here, add the closure that I just described, the row provider, and return a row type.

Luckily like any good TV demo I had one baking in the oven all along so we'll just use that one.

Let's take a look at how that looks now.

Now this is a lot better.

My rows are a little bit more compact.

I've added some more details to each one and I can even see at a glance which ones are favorited, and that's really nice.

And the great thing here is that my list implementation is still completely shared.

So if I still had if I had like really advanced filtering, sorting, or grouping logic, or if it was especially fancy, let's say I had some asynchronous work that was going to a database or to the internet, you know personally I only want to write that code once.

And now we can and we don't have to compromise on our design to do it.

The next thing that I'd love to be able to do is to double click one of these rows to pop it out into its own window.

And that's also really easy.

I'm going to show you how.

The first thing that we need to do is create a window and on the Mac, even when we're defining our views with SwiftUI, we use AppKit to define our windows.

Now I could do this in my storyboard but the code is really short so I'm just going to show it to you.

We have a window controller and then I've defined a convenience initializer that takes a SwiftUI view, puts it into a hosting controller, and then creates a window around that hosting controller.

I've also written a little bit of convenience code here that just keeps track of which windows exist per landmark already so that if I double click on a row that already has a window, it'll bring the existing window front instead of creating a new one every time.

Let's go back to our list and add this integration.

So, detail let's add a quick convenience method shared to show a window for a given landmark.

And then to attach it to my row, I can just add a tap action with a count of two because I only want it to recognize double clicks, and then in this tap action I'll call my show detail for landmark method.

Now, when I double click on my rows, I can pull them out into their own windows and I can put them side by side, arrange them however I'd like.

And because these are still AppKit windows I can use all of the great windowing features that are built in.

So if I like tabs I can merge them into tabs and it's just like that.

I get that completely for free which is really great.

[ Applause ]

And with that, I think that the Mac version of this app is starting to look pretty good so I'm going to go ahead and go back to our slides.

So now that we've seen SwiftUI on AppleTV and Mac, it's time to turn our attention to Apple Watch.

You know SwiftUI is the first truly native framework for building apps on Apple Watch and I think it's going to really broaden our horizons for what's possible.

And to walk us through some of those possibilities, I'd like to hand it over to my colleague Meghna.

[ Applause ]

Thank you.

[Applause]

Thanks Jeff.

With SwiftUI and all the amazing things you've learned so far you are bound to be on track to build an app that provides an awesome experience on all devices.

Hi, I'm Meghna and now I'm going to talk to you about bringing this great experience to your Apple Watch App.

While your experience may be rooted in your application, building for WatchOS means so much more.

Complications, Siri shortcuts, and notifications all contribute to showing the most timely information right on your Apple Watch face.

Apple Watch is all about showing the right information at the right time.

For the purposes of this talk, I'm going to focus on the app and notifications.

We'll start with talking about how SwiftUI allows you to display elements and lay out your Apps UI like never before.

But first things first.

A good rule while building an Apple Watch experience is to aim for the primary information or the most critical action to be available within two or three taps.

While designing this experience, the aim isn't to shrink down your iPhone app but to bring the most timely and relevant actions to the context of your wrist.

With that, let's dive into some SwiftUI simple concepts.

If you have content that exceeds the bounds of a full screen, you can wrap it in a SwiftUI scroll view.

SwiftUI also gives you this great new digital crown rotation API which lets you completely control rotation and haptics.

This API also opens the door to using the digital crown in all new ways to modify interface elements.

This is something that was never possible before.

You're also probably familiar with groups in WatchKit.

SwiftUI now gives you much more powerful ways to organize your content with horizontal and vertical stacks.

Tabulating information has never been easier than with lists and with list sections.

Lastly, identifying what your users care about the most on your Apple Watch App will help you decide what kind of data to surface.

With the views and controls provided by SwiftUI, you can easily build an interface that conveys the most crucial information first.

Notifications are a great way to give timely updates, however, too much information or content that isn't useful may lead people to turn them off for your app.

SwiftUI gives you the ability to easily provide intuitive and beneficial controls so people can respond from within your app and not have to dismiss the notification.

Making your notifications actionable as possible, you can allow people to quickly respond.

When you send your notification can be just as important as what you send in it.

Try to use what you know about how someone uses your app and with that information you can send the most timely information at the most appropriate time.

With these powerful new SwiftUI concepts and a better understanding of what makes a great Apple Watch experience, let's take a look at the landmarks app where we put some of these concepts to use.

Using the app you've built with SwiftUI for all the other devices you're going to have a functional Apple Watch App.

However, it may not be the best Apple Watch experience.

I'm going to show you how, with a few tweaks and updates, you're going to be able to bring this app more in line with the context of the wrist.

Well the first thing you see here is that we've built a landmarks list.

For the watch landmarks, we've gone ahead and customized the details cell.

We've included an image for some context.

We've included some tool details and we've also added some contact capabilities.

Now some of these things like the contact capabilities don't add too much value to say, an AppleTV app but they work great inside an Apple Watch App.

But that was still way too much content to scroll so what we decided to do is to narrow it down to just our favorites.

To do that we created a simple Swift filter.

Since we've narrowed this data down, we also wanted users to have an option to see all the landmarks if they chose to.

That was possible with adding this button.

This button simply toggles the state between showing all and showing favorites based on the view that you're in.

SwiftUI gives you this unique ability to pick the pieces that interest you for your app and compose the views that work best for your interface.

We wanted to be able to focus on each cell more when we scroll.

With SwiftUI we were able to do that with the carousel list style.

This list style is great when you have a fewer number of cells or when you have cells with interactive controls.

Here our cell has buttons for contacting, for making a phone call, for adding or removing the landmark from favorites, and having some navigation capabilities.

Lastly, notifications.

For the landmarks app we wanted to notify you when a new tour has been added.

We wanted to add some images so you can decide if you're interested in this tour.

And also give you the ability to book it from within the notification.

Using the power of Swift, you not only have the textual information but you also have this gorgeous, rich animation moving the images.

Instead of just talking to you about it I'm going to show you how we built this.

So what you see here is that I've created a structure for a new tour notification.

Now I've already gone ahead and hooked this notification up to my notification controller which means that whatever is in this body is what you see inside the notification after I run this scheme.

This struct [phonetic] takes in a landmark as a parameter which is what the notification will ideally pass to it.

Now let's go ahead and add some text.

Okay so what we've done here is that we've created a stack that includes some textual information.

The only reason I have a stack here is because I'm going to add some more data inside this.

In here we have decided a struct called slideshow which takes in an array of strings.

These strings are image names.

We have a variable which is called the current index which is essentially just to track which image you're on at this point.

Tour image is a custom struct that I've created which is a view.

It takes in an image name that aligns the image correctly inside my app.

Let's see how this looks in the previews so far.

Now, the next thing I want to be able to add here is an ID for an image.

That way when we animate this we will have a proper track of what view needs to be inserted and what view needs to be removed.

At this point it looks like okay we have our text here, great at this point it looks like we can go ahead and add this slideshow struct inside our notifications body.

All right so once this updates we should be able to see this view here.

This looks great.

Now like we talked about here, we should be able to support multiple images inside this struct.

For that, we would need to calculate the next index.

Let's go ahead and do that.

Now in here I'm simply calculating the next index and I'm updating the current index.

What I also want to do is animate this change.

With a simple animation, every time my current index is updated it will have some fluid string animation which looks pretty good.

Now, we've created this but we haven't actually hooked it up to anything.

Inside our ZStack ideally what we'd want is that after a particular interval in time we'd want the image to change and move on to the next image.

So I created an extension on a view which has a view modifier.

Show next image is a simple view extension which essentially invokes a timer that after every two seconds switches on to the next image index.

Now the last thing I want to add here is this gorgeous slide transition we saw, which is this easy command right here.

Okay, let's see how this looks.

Okay so we have these images scrolling through.

We have some actions that we had hooked up to the notification controller before.

As you can see [applause] thank you.

[ Applause ]

Like you see, with very few changes we were able to create this gorgeous, rich notification which in WatchOS was never a possibility before.

With that, let's go back to Jeff.

[ Applause ]

All right, thank you Meghna.

I think it's so cool to see something so rich and interactive appearing just in the context of a notification.

I think SwiftUI is going to really broaden the horizons for what's possible on WatchOS.

Now this has been just a whirlwind tour so let's kind of revisit and sum up what we've learned today.

The first thing is that when we're thinking about bringing an application to a given device, take a design first approach.

This isn't about saying that I've got this code and I'm going to try and get it working over here.

It's thinking about what's the right expression for my app on this device and working backwards from there.

But, you can share some code sometimes.

For example, we didn't really call it out but every demo that you saw today is effortlessly sharing the model code.

The model code has been compiled into each target identically.

And you can share view code, you just have to use good judgment about when you do it.

And SwiftUI can help you along the way by making it really easy to re-factor out small, reusable components that make more sense to reuse across devices.

And finally, we're not here to write once and run anywhere.

The real power is in your knowledge.

When you learn once, you can apply that to any device and I think that's really powerful.

As always, this talk lives online.

There you can see the video replay and get associated resources and I want to thank you for your time.

We cannot wait to see what you build with SwiftUI.

[ Applause ]

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US