Quick Look Previews from the Ground Up

Session 237 WWDC 2018

Quicklook Previews are an easy way preview documents in your app. Hear about the basics as well as some advanced implementations. Learn to present a variety of types of documents from within your app without reinventing the wheel, and make sure your custom file format works great with the built-in support offered by iOS.

[ Music ]

In this session we are going to tell you all about Quick Look.

Welcome to previews from the ground up.

My name is Raffael and I'm going to present together with Maxime, both software engineers at Apple.

We are going to start with a brief overview of what Quick Look is.

Then we're going to show you how to adopt the Quick Look Preview Controller in your application.

And then we're going to explain how to provide custom Quick Look previews and custom thumbnails for your own file formats.

Let's jump right into it, what's Quick Look?

Quick Look is all about previewing documents, it allows you to present documents without the hassle.

More precisely, Quick Look is an iOS framework that provides multiple core features to you as a developer.

It allows you to preview documents of several commonly used file formats, to provide custom previews for files of your very own file format, and to provide thumbnails to the system for files of your own custom file format.

Quick Look is in fact already used by many of Apple's first party applications.

For example, in files to present your documents that you have in the Cloud.

Or in Mail and Notes to preview your attachments.

And in Messages to show your pictures and videos that you've sent.

So who is this session for?

Well if you want to know how to present documents in your application without having to implement all the common features the users are used to you're in the right session.

You also might own a custom file format which iOS doesn't support natively and you want to make sure that your file format is properly handled by iOS with custom thumbnails and previews stay here if you want to learn more about this.

And no matter if you're a newcomer to iOS or if you already have an app we're going to guide you step-by-step.

By the way, if you haven't checked it out yet you should definitely take a look at last year's session, Building Great Document-based Apps in iOS in which we have introduced the UA document browser view controller document browser view controller and also have covered the basics of Quick Look preview and thumbnail extensions briefly.

There's also going to be a document browser one-on-one session this year which we highly encourage you to attend if you're interested in file handling on iOS.

Quick Look has been around for quite a while already.

It's been introduced with the iOS 4 SDK.

The main class you're interested in is to [inaudible] preview controller which is a view controller to preview documents.

It uses the classic data source and delegate pattern that you already know from your UIKit and other frameworks.

And presenting Quick Look with a beautiful [inaudible] transition couldn't be easier with the API that we give you.

Why would you want to use Quick Look?

Well if you have a similar use case to files, mail or the other case to files, mail or the other apps we've shown you before Quick Look is the perfect choice for you.

Quick Look comes with everything you need out of the box.

It supports the commonly used file types and it provides that native user experience that your users are used to from other first party iOS apps.

We made sure Quick Look has a create performance on all devices, so that all the animations and gestures are fluid.

And you might be dealing with files from untrusted sources, but don't worry we got your back.

Quick Look comes with a sophisticated security model that keeps your application safe.

Let's take a look at the supported file types.

As you can see all the common types are in here.

Media files such as images, audio files and videos, documents such as PDFs and office files, but also zip archives.

Previewing a zip archive lets you look into the contents of the archive and view the contained files individually and share them for example.

Now if your custom file format is missing in this list don't worry.

Last year we introduced a new extension point for implementing Quick Look preview extensions.

Preview extensions allow you as a developer to create a preview for files of your very own custom file format.

We will cover this in the second part of the session.

And this year with iOS 12 we have also added support for the new AR file format USDC, so with just a few lines of code you get a fully immersive augmented reality experience in your application.

Okay, now let's talk about user experience.

For each of the file types shown before we made sure that Quick Look provides the best possible preview on your mobile devices.

For example, when previewing images you're able to zoom into the images conveniently.

You're also able to close Quick Look with a swipe down gesture.

In PDF documents you get a sidebar with thumbnails for easier navigation.

In spreadsheets you can switch through the individual pages of the document.

And in media files we show a scrubber that allows you to go back and forth and so on.

You get the idea.

So when you choose Quick Look your users get all the gestures they are used to from other applications.

So what are some common use cases for using Quick Look?

For example, you might want to let the users zoom into photos or you want to be able to flick through a collection of photos left and right.

You want to play audio or video You want to play audio or video files without having to deal with lower-level frameworks.

Or you want to present for example a scrollable and zoomable user agreement PDF to the user.

Use Quick Look for this.

But Quick Look shouldn't be misused, here's when not to use Quick Look.

Quick Look is all about previewing but doesn't provide editing features.

So if you need to provide functionality such as image editing, PDF management or movie trimming you need to choose a different approach.

Similarly, if you need more advanced playback control for your videos Quick Look is probably not the best choice, you can use AVPlayer instead.

Quick Look is meant to be presented full screen.

If you simply want to present an image, a video or a document embedded in your layout together with other views surrounding it you probably want to use you probably want to use UAImageView, AVPlayer, WKWebView or other kind of views instead.

Also note that it's not supported to customize the view hierarchy of Quick Look.

Please don't try to add views on top of the previews the navigational toolbar, this is simply not supported.

So now that we've introduced Quick Look, let's take a look at how to actually make use of our APIs.

If you want to present documents to the user as a first step you instantiate a new QLPreviewController which is basically a UIViewController.

Next, in order to tell the preview controller which documents to preview, you need to assign a data source to it.

The data source is an object that conforms to the QLPreviewController data source protocol.

protocol.

We'll take a look at this in a second.

And as a third and last step, all you have to do is present the view controller.

Let's take a closer look at how the data source works.

Your data source has to conform to the QLPreviewController data source protocol.

This is a protocol that requires two methods.

First, you need to return the number of items that your preview controller should preview.

It should provide more than one item the users will be able to swipe left and right to flick through the documents.

Next, Quick Look then will ask you for one or more QLPreviewItems depending on what number you've previously returned.

Okay what's a QLPreviewItem?

It's a protocol that acts as an abstraction for your documents.

For Quick Look a preview item is basically the URL, where to find basically the URL, where to find the document on disk and optionally a title that Quick Look will show in the navigation bar.

The class representing documents in your app needs to conform to the QLPreviewItem protocol.

But by the way, NSURL already conforms to the QLPreviewItem protocol, so if you don't need custom titles you can simply return NSURL instances in your data source without implementing the protocol yourself.

Let's take a look at an example.

In this scenario our view controller that presents Quick Look acts as the data source of the QLPreviewController.

Therefore, we let it conform to the QLPreviewController data source in an extension and we implement the two methods.

Here we are using an area of file URLs that acts as the model.

We return the number of URLs that we have in the number of that we have in the number of preview items in controller method.

And then each URL respectively referenced by the index in the previewController controller previewItemAt index method.

Okay we've set up our preview controller and it knows what files to preview, so we are ready to actually present the view controller.

There are two ways for doing that.

You can either present the preview controller modally on top of the current context or you push the preview controller into a UINavigationController.

Both ways work great and you need to decide what fits best in your situation.

To present it modally you do what you do with any view controller you call present.

Here's an example of what a modal presentation can look like.

If you have a UINavigationController and prefer to push the preview prefer to push the preview controller instead you use pushViewController.

This is what it looks like.

The QLPreviewController class provides a few more methods that I would like to highlight.

First, if you want to know if Quick Look is capable of previewing a certain document use the canPreview item class method, this will return true if the document matches any of the supported default file types or if there is a preview extension available that can handle the file.

The data source we've already covered.

Reload data reloads the list of documents your preview controller should present.

If this list ever changes while the preview controller is currently presented use this method to trigger a reload.

If you need to obtain the index of the currently previewed item in your list of preview items remember the user can swipe left and right to switch to a different one, use the current previewItemIndex variable.

This is both a getter and a setter, so if you want Quick Look to start with a particular item when it's being presented set the index to the right value.

Last but not least, preview controllers also have a delegate.

Let's take a look at the QLPreviewController delegate protocol now.

If you assign a delegate to your preview controller you get more ways to control how Quick Look behaves.

It also lets you react to Quick Look presentation events.

Note that all of the methods in the QLPreviewController delegate are optional.

You don't have to implement them and in fact you don't even have to assign a delegate at all.

to assign a delegate at all.

The protocol hosts a bunch of methods you can implement.

The first two methods lets you react to the event that Quick Look is about to be dismissed by the user and also that the dismissing is now complete.

You might want to use these methods to update the view controller that is presenting Quick Look right now.

Next, the preview controller should open URL for item method allows you to prevent Quick Look to follow a link contained in previewed documents.

With this method you can for example prevent the user from leaving your app when tapping a URL or a phone number contained in a PDF.

And last but not least, as promised before the QLPreviewController delegate protocol also provides API to get a smooth zoom animation when Quick Look is presented and Quick Look is presented and dismissed.

With these methods a thumbnail that is on screen in your user interface can transition into a full Quick Look preview when tapping it.

Imagine an email attachment or a photo inside a conversation view which you can tap to show it full screen with Quick Look.

We made it super easy for you to get this cross fade zoom animation in your application.

If you implement one of the two approaches in your delegate Quick Look will ask for the information that is needed for performing the zoom.

This is basically the rectangular area the animation should start from when presenting or end in when dismissing Quick Look.

Either you provide the frame and the image of the thumbnail or and this is the preferred way of and this is the preferred way of doing it, you use our mode and method in which you simply return the thumbnail as a view.

With this approach you don't have to worry about coordinates Quick Look will do all the heavy lifting for you.

And this is what it can look like.

Note how the thumbnail transitions into the full-screen Quick Look preview.

All right now it's time for a demo in which we would like to show you what we've just covered.

Okay, here's an iOS project and instead of talking about it let's just press the play button to see what we've already prepared and what we are dealing with here.

We are calling this Wildlife Explorer and it's a very simple app.

It basically displays a grid of photos and each of these photos that we see here acts as a that we see here acts as a thumbnail for what's behind it once you tap it.

For example, tapping the elephant should show a large photo of the elephant in full screen and tapping the giraffe should preview an entire PDF about all sorts of giraffes.

Right now we can't do anything else than just looking at it, tapping won't do anything yet so let's fix this.

Now this application is fairly simply structured.

For displaying the grid of photos we use a CollectionViewController.

When initializing it we obtain a list of URLs of documents that are bundled with the application like the elephant we've just seen.

We use that list to initialize what we call a document data source.

This object serves as the model for the collection view in the implementation of the implementation of the UICollectionViewDataSource protocol.

Here we return the number of documents we have just gathered and then create a cell for each of the documents with a thumbnail as the image of the cell respectively.

And that's pretty much the core of the application so far.

Now let's add what we've talked about before.

When tapping a cell we would like to show Quick Look with the right document.

We've already made sure that we have a method that is called when the user has just tapped a cell.

To show Quick Look we create a new QLPreviewController in here and configure it.

We create a new controller, we assign the document data source to it as the data source and then make sure Quick Look shows the correct preview when it's presented by setting the right CurrentPreviewItemIndex.

Great, now Xcode is already complaining about our new code, it doesn't know QLPreviewController yet.

We need to import Quick Look first and therefore we return to the top of the file and import Quick Look.

Done. The next thing Xcode complains about is the data source.

The document data source that we assigned to the new preview controller doesn't seem to conform to the QLPreviewController data source protocol yet which we have talked about earlier.

To fix this let's switch to the implementation of the document data source.

The document data source is a very simple kind of object, it simply owns an area of URLs so far.

We need to add the QLPreviewController data source protocol to the list of protocols that this class implements.

Next, we implement the missing methods.

As you can see the way we use the document data source here is very similar to the way we use it for the collection view.

In the numberOfPreviewItems method we return the number of URLs that we have gathered before from our documents folder.

And then Quick Look asks for the And then Quick Look asks for the individual QLPreviewItems and we return the right URL referenced by the index.

Great, the data source has been properly set up so we can go ahead and actually present the preview controller.

Therefore, we return to the didTapCollectionCell method and add the missing method call.

Let's check out how this looks like.

All right we are back in grid and now when tapping a cell Quick Look appears displaying the right document in full screen.

Note how easy it is to present images and even PDFs in full screen with all of the gestures screen with all of the gestures that you are used to.

We can zoom into the document with two fingers, we can select text, and even copy it.

And once we are done we can use a pinch gesture to dismiss Quick Look again.

So what we are using here to present Quick Look is a modal presentation style.

As I've explained earlier, we can also present Quick Look with a push animation.

Therefore, we simply tell the application's navigation controller to present the preview controller by pushing it on top of the current one.

Let's take a look.

As you can see, this is a different style of presenting Quick Look and it works just as fine as presenting it modally.

Okay Quick Look works and now the last thing I would like to show you is how to use the Quick Look delegate in order to get a beautiful zoom animation when tapping a thumbnail in our grid.

First, we switch back to the modal presentation style which is needed for the zoom transition to work.

Then we need to assign a delegate to the preview controller and in this case, we assign self.

However, self doesn't conform to the QLPreviewController delegate yet, so let's add it to the list of protocols.

And now as the last step we implement the magic method which tells Quick Look which view to use as the source for the zoom animation when it is about to be presented.

As you can see, we are using the image view of the most recently tapped cell which we keep a reference of and return it to Quick Look.

That's literally all we have to do to make the zoom animation work.

Quick Look will call this method when it's presented and when it's dismissed.

Let's try it out.

Now when we tap a thumbnail notice how the thumbnail is animating to the full-screen preview.

Also observe no matter how we dismiss the preview it beautifully transitions back to the right origin.

Great, that's it for the demo, back to the slides.

And now I would like to hand it over to Maxime who is going to tell you all about previews and thumbnail extensions.

Thank you Raffael.

So as you have seen, Quick Look makes it super easy to add a powerful previewing feature to your app.

But there is more to talk about.

The first thing I want to show you is how to extend Quick Look's previewing capabilities by providing a preview for your own file format.

We have listed the file types that Quick Look supports natively before.

However, since iOS 11 this list However, since iOS 11 this list can be extended by bundling a preview extension with your iOS app which allows you as a developer to provide previews for your custom file formats.

You should provide a preview if you're in a custom fil format and you'd like this one to be previewed by Quick Look just like any other native type.

File types that are meant to be shared are usually good types to create an extension for, especially if you want your users to preview the content easily after receiving a file in an app like Mail, Messages or in a Note for instance.

And then everything works together and your application that is using a QLPreviewController with a file that is not natively supported will benefit from your preview extension.

Here is an example of what you can achieve thanks to a preview extension.

We have built a sample app that can be downloaded from Apple's can be downloaded from Apple's website that allows one to create customized and interact with Particles.

Since we wanted to share our cool Particles to other users we created a new file format, the particles file format.

Each file represents a particle system and you can configure all sorts of [inaudible] systems.

Now let's say you share a particles file with your friends.

When previewing them in messages or as an email attachment for instance [inaudible] get to see is a blank screen, that is certainly not what we want.

But by implementing your preview extension for our particles file format it will replace that blank screen with a beautifully rendered three-dimensional interactive particle system.

How good is that?

I am sure you now want to learn how you can make your own preview extension for your file formats.

First, you will need to add a new target in your existing application project.

To do so you will have to select the Quick Look Preview Extension template in Xcode.

After that several files will be generated for you by Xcode.

The PreviewViewController class with a basic implementation.

This is where you will have to add code for your preview.

The storyboard that has the PreviewViewController as its entry point.

And an Info.plist that's the first thing you will want to edit.

Let's take a closer look at it.

To get started the attribute we are the most interested in is named QLSupportedContentTypes.

This is the one that is highlighted on the screen shot.

This is an array in which you list all the file types for which your extension can provide previews.

Please note that you can only Please note that you can only provide previews for UTIs you own and export.

When Quick Look can't natively preview a file type it will make use of the content types added to this array and select an extension that can handle previewing it.

So make sure to list all file types [inaudible] extension support.

Let's see how we achieve this with our Particles app.

As you can see Particles declares and exports a new particles file type.

Its identifier is [inaudible] example.applesample code.particles.particles.

Since we wanted our extension to support particles previews we added this identifier to the QLSupportedContentTypes of its Info.plist.

By the way, if you're interested in UTIs you should check out the Documents Manager session of this year.

When a new preview has to be generated for a file type [inaudible] Quick Look will create a new PreviewViewController instance and calls it preparePreviewOfFile at URL completionHandler method.

This method is part of the QLPreviewingController protocol and is mandatory to provide previews for a file.

Quick Look will display [inaudible] while waiting for your extension to be ready to display the preview.

All you have to take care of is loading the contents of your preview and calling the completion handler as soon as your extension is ready.

All right that's it for the preview extensions, let's go one step further.

Similarly to previews you can also provide thumbnails for files of your own file format.

Let's talk about Quick Look thumbnail extensions.

A thumbnail is an image of a limited size that represents the contents of a file.

contents of a file.

There is throughout iOS and macOS to allow users to identify files officially without having to open them to the file contents.

For instance you can see on the screenshot how iOS makes uses of them in the file tap.

iOS can generate thumbnails for different file types, images, videos, PDFs, text files, and USDZ files.

Now you may have noticed the blank icons on the left.

This is because these are particles files and iOS doesn't know how to generate thumbnails for this file natively.

But don't worry we are going to show you how to create a thumbnail extension that you can use to improve this situation for your custom file types easily.

Look at how great these thumbnails look for particles files thanks to the thumbnail extension we have added to our app.

Thumbnails provided by this extension appear in the Files app, as well as in any UIDocumentBrowswer ViewController-based app.

They also appear in the Quick Look list, that you can see when tapping the list button when previewing multiple files in Quick Look.

If you have custom file types that the user can share and interact with you will likely want to provide a certain extension with your app.

Let's now see how you can do so.

Creating a thumbnail extension is as just creating a preview extension.

To do so add a new target in your existing application project and select the Thumbnail Extension template.

Xcode will generate for you two files, the ThumbnailProvider class with a basic implementation.

This is where you will have to add the code that takes care of generating thumbnails.

And an Info.plist this is just And an Info.plist this is just like for the preview extension, the first thing you will have to edit after creating your extension.

As in the Info.plist of the preview extensions the Info.plist of the thumbnail extensions have a QLSupportedContentTypes array that needs to be filled with the content types that your extension supports.

So make sure to include in QLSupportedContentTypes all the content types for which your extension can generate thumbnails.

After setting up your extension you will be able to start implementing your QLThumbnailProvider subclass.

You have two ways to provide a thumbnail for a file.

You can [inaudible] use it CoreGraphics or UIKit [inaudible] techniques or you can return an image file URL.

You will have to override the provideThumbnail for request provideThumbnail for request handler method in your QLThumbnailProvider subclass.

We extensively covered this part of the Quick Look API in your session for WWDC 2017, Building Great Document-Based Apps in iOS 11.

So if you'd like to provide thumbnails for your custom file types I highly encourage you to check it out.

In a nutshell, you will need to make use of the parameters contained in the QLFileThumbnailRequest of the method.

The URL of the file, the maximum and minimum sizes of the thumbnail, and its scale.

For each thumbnail request the API expects you to create a QLThumbnailReply object.

This object will have to take care of generating the thumbnail.

You will have to provide it to Quick Look through the completion handler of the method.

All right let's see all of this in action it's demo time.

in action it's demo time.

Let's start by taking a look at how things look like after installing the Particles app without any Quick Look extension.

All right we don't have any file yet, let's create a new one by pressing the + button.

What you can see here is the particle editor.

Let's create a file particle system, we change the color a bit, and save the document.

Well as you can see we don't get to see the beautiful particle system we just designed.

[Inaudible] of that by adding a thumbnail extension to our application.

Now let's save the file to a [inaudible] and see how the preview looks like in Quick Look.

All right let's open the file format.

All we see is a blank screen, we can do better, let's improve this too.

Let's switch to Xcode and implement a preview and a implement a preview and a thumbnail extension.

We already have an existing project containing the extension setup.

We are going to use these as a starting point and add the two extensions.

As mentioned previously we need the Info.plist of our extensions to be configured so that the system knows we are able to provide previews and thumbnails for particles files.

So Particles app defines its own file format in the exported UTIs section of the application target.

We need to configure the extensions to use that UTI in the Info.plist.

As you can see the QLSupportedContentTypes of the Info.plist of the preview extension does contain the identifier of the UTI of the particles file format.

And this is also the case of the Info.plist of the thumbnail extension.

So the only thing left to do is to actually implement these extensions.

Let's start with the preview extension.

As mentioned in the presentation As mentioned in the presentation we need to implement this method, preparePreviewOfFile at URL completionHandler.

Our main app Particles already has a view controller class which [inaudible] the particle system on screen.

We are going to reduce [inaudible] controller in our extension.

We are going to create a helper method that will take care of loading such a view controller and adding it to the view hierarchy.

As you can see present particleViewController for a document simply creates a particleViewController and passes it to the document it received so that the particleViewController can render the particles that the document represents.

We still need to call this method from preparePreviewOfFile at URL, so let's do it.

We first create a document that is a subclass of [inaudible] document.

We open it and once it is open and usable we call our helper and usable we call our helper method that will displace a particleViewController.

Finally, we may not forget to close the completion handler to notify Quick Look that our view controller is loaded and ready to appear on screen.

Our preview extension is now ready.

Let's implement the thumbnail extension.

All we have to do here is to implement the provideThumbnail for request handler method.

So request provides several properties that you need to consider when rendering a thumbnail.

In this example we will make use of the file URL as the maximum size of the thumbnail.

Note that there are also a scale and minimum size properties, but in the case of our particle system we don't use them.

We then create a drawing block that we are going to provide later [inaudible] completion block.

In this case, we call the helper method that will take care of method that will take care of drawing the thumbnail, drawThumbnail for fileURL, contextSize.

We are going to implement this helper method in a second.

You may have noticed that our drawing block returns a Boolean, this flag indicates if the thumbnail was successfully drawn or not once this block will be used to generate the thumbnail.

Let's now see how we draw our particle thumbnails.

To draw the thumbnails we make use of the URL of the file and of the size of the context we will draw into.

In this case, we all know the maximum size of the thumbnail request since we can generate particle thumbnails of any size.

Our method first creates a document that represents the file and attempts to open it.

If this fails it returns false to indicate that it could not generate a thumbnail.

After opening the file it then creates a particleViewController that will be used to render the particles file.

Then it takes a snapshot of the Then it takes a snapshot of the particleViewController and uses it to draw the thumbnail.

We close the document before returning true to indicate that we successfully have generated a thumbnail.

Now that we have [inaudible] to generate thumbnails we need to create our [inaudible] reply.

We created out of the context size, which in this case is the maximum size and the drawing block.

Also we have our reply object we provided through the completion handler [inaudible] parameter, which in this case is new since we always add them to draw thumbnails for particles documents.

If [inaudible] while drawing it the thumbnail block success value will indicate it, so the thumbnail can be discounted later.

We are finally all set, let's run this code and see how this looks like.

Wow. We now see a beautiful thumbnail for our fire particles file.

This looks so much better than before.

Now let's check our preview extension.

Okay.

So we are in Note and Quick Look is still showing the blank screen from the previous time we tried to previewing your file.

Let's dismiss Quick Look and present it again.

We now see our great particles preview, note how easy it was to make our custom file format [inaudible] in iOS.

And that's it for the demo.

So what have we learned today?

First, we have shown you how easy it is to add powerful previewing capabilities to your application by using the QLPreviewController of Quick Look.

Then we have taken a look at Quick Look's extension points.

Preview extension allows you to have your custom files preview by Quick Look just like any native file type.

While the thumbnail extension is used to provide thumbnails of your own file types to iOS when needed.

Together these extensions make Together these extensions make your file formats first-class citizens in iOS.

And that's it for this Quick Look session.

If you would like to have more information you can check out Apple's website.

Thank you for your attention.

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