What’s New With PhotosPicker in iOS 16
PhotosPicker in iOS 16 has a robust set of features for users to view and select assets, such as images and videos. By Felipe Laso-Marsetti.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
What’s New With PhotosPicker in iOS 16
15 mins
Working with photos is commonplace in today’s era of mobile apps, and PhotosPicker
is usually the go-to choice, especially when working with SwiftUI.
iOS 16 brings some important and useful enhancements to improve your development workflow with PhotosPicker
:
- Improved SwiftUI implementation.
- New filter options that can be back-ported to iOS 15.
- Compound filters.
- Availability for macOS and watchOS.
- Updated design for iPadOS.
In this tutorial, you will learn how to work with the PhotosPicker API and also see what is new as of iOS 16.
For this tutorial you should have at least some beginner knowledge of Swift and SwiftUI.
Without further ado, you’ll jump right into an awesome tutorial that leverages PhotosPicker
and iOS 16.
Understanding PhotosPicker
PhotosPicker
is a SwiftUI view that allows you to select one or more assets from your photo library. It’s part of the PhotoKit
framework for working with videos and images from your device’s photos app.
With as little code as the following:
@State private var photosPickerItem: PhotosPickerItem?
PhotosPicker(selection: $photosPickerItem, matching: .images) {
Label("Select Photo", systemImage: "photo")
}
You can have a button that, when tapped, shows a robust, native view for your users to pick photo or video assets from their photo library.
Some of the customization options you have are changing the button’s image, label or tint color.
You can also add filters to control what types of assets can be selected. If you’re working on an app that relies exclusively on Live Photos, hiding all other asset types will save you and your users time.
Once your users have made their asset selection, you’ll work with PhotosPickerItem
, a representation of your selections in PhotosPicker
, to get information about the selection or the actual assets themselves.
How about seeing all of this in action?
Getting Started
Download the starter project by clicking Download Materials at the top or bottom of the tutorial.
You’ll see a project called Foodvorite, a journal app that keeps track of your favorite foods with images. The project uses sample, hard-coded data for meals, since this tutorial’s focus isn’t on adding or editing meals or on persisting them with your photo selections.
Open the project to see how it’s set up. Then, open Meal.swift to look at the model that represents a meal entry in the app. A meal consists of an ID, title, notes and data for the associated photo.
You’ll use four views in the project:
- MealsView: Shows a list of all your meals.
- MealRow: View that makes up a row for a meal entry. The row shows the meal’s title, notes and a thumbnail of the photo (if a selection has been made).
- MealDetail: View to show all the details of a meal and a large image of the selected photo (if available).
- PhotoView: Helper view to show either a placeholder image or a photo in two different sizes — one for the thumbnail and a larger one for the meal details.
Build and run the project to see the app in action and familiarize yourself with it.
Implementing a Photo Picker
Time to implement a PhotosPicker
view, so meals no longer show the placeholder image.
Open MealDetail.swift, and add the following property as part of the view:
@State private var photosPickerItem: PhotosPickerItem?
This property is used with PhotosPicker
to handle any individual asset selections the user makes.
Next, at the bottom of the VStack
but still inside it, add the following code:
PhotosPicker(selection: $photosPickerItem) {
Label("Select Photo", systemImage: "photo")
}
Here, you add the PhotosPicker
view with the photo SF Symbol as the button icon and Select Photo as the button text.
The initializer for the PhotosPicker
view takes one parameter, a binding to an optional PhotosPickerItem
. To use PhotosPicker
, you need to add an import for PhotosUI
, which was already done for you as part of the starter project.
Build and run. Select any meal from the list to go to the details. Notice the button that’s now showing.
Tap the photos picker. The photos picker will show all the available photos and videos on your device.
Excellent!
You’ll handle selections in a little bit, but for now, how about styling the button so it looks better?
Still inside VStack
in MealDetail.swift, add the button inside the horizontal stack with some spacing and padding:
HStack(spacing: 10) {
PhotosPicker(selection: $photosPickerItem) {
Label("Select Photo", systemImage: "photo")
}
}
.padding()
This helps add some padding so the button isn’t squished with the rest of the view’s content.
Next, add these modifiers to PhotosPicker
:
.tint(.accentColor)
.buttonStyle(.borderedProminent)
The two modifiers above help give the button the project’s accent color and a large, prominent visual style.
Build and run. Navigate to a meal’s details. Look at the select photo button.
It definitely looks better than before!
Handling Selections
So, you’ve added the Select Photo and the button it shows. You can even select a photo from the picker. This action dismisses the picker even though nothing happens at the moment. Time to take care of that!
Also in MealDetail.swift, add the following function inside struct
and below body
to load the photo’s data that your user selects in the picker:
private func updatePhotosPickerItem(with item: PhotosPickerItem) async {
photosPickerItem = item
if let photoData = try? await item.loadTransferable(type: Data.self) {
meal.photoData = photoData
}
}
This is an async
method that takes PhotosPickerItem
as a parameter. Within it, you assign the item parameter to the view’s photosPickerItem
property.
You then call loadTransferable
on PhotosPickerItem
to acquire the asset’s data. This method is asynchronous and can throw an error, so you mark it with try? await
accordingly.
If the method returns valid data, then you store it in the meal’s photoData
property.
So, where can you call this method from? Still within MealDetail.swift, add the following modifier to ScrollView
, after the navigation modifiers:
.onChange(of: photosPickerItem) { selectedPhotosPickerItem in
guard let selectedPhotosPickerItem else {
return
}
Task {
await updatePhotosPickerItem(with: selectedPhotosPickerItem)
}
}
This code block will get called whenever the photosPickerItem
changes. Inside, you have a guard
statement to ensure you have a valid PhotosPickerItem
; otherwise, you return
.
If there’s a non-nil item, you call the method you just wrote within a Task
— since it’s an async
method — and mark it with await
.
Build and run. Navigate to a meal’s details. Tap Select Photo. Select a photo for your meal.
Yay! How cool is PhotosPicker
?
Next, navigate back to the list of meals. Notice the row corresponding to the meal you just selected a photo for.