Previous to iOS 16, if it’s worthwhile to show a photograph picker for customers to decide on pictures from Picture library, it’s a must to depend on PHPickerViewController
or the older UIImagePickerController
of UIKit. It’s not tough to make use of it as you may combine UIKit parts with UIViewControllerRepresentable
. That mentioned, it will be nice if the SwiftUI framework comes with a local view for picture picker.
In iOS 16, Apple lastly brings PhotosPicker to SwiftUI that it has the identical functionalities as its UIKit counterpart. In case your app will solely assist machine working iOS 16 or up, you need to use this new view for dealing with picture picks.
Let’s see the way it works with some pattern code. Please word that it’s worthwhile to use Xcode 14 beta 4 to comply with this tutorial.
Utilizing PhotosPicker in SwiftUI
The PhotosPicker
view is bundled within the PhotosUI
framework. Earlier than utilizing it, it’s a must to first import the framework:
Subsequent, we declare a state variable to carry the chosen picture:
@State personal var selectedItem: PhotosPickerItem? |
It’s fairly simple to deliver up the pictures picker. Right here is the essential utilization of PhotosPicker
:
PhotosPicker(choice: $selectedItem, matching: .photographs)) { Label(“Choose a photograph”, systemImage: “picture”) } .tint(.purple) .controlSize(.giant) .buttonStyle(.borderedProminent) |
You instantiate PhotosPicker
by passing it a binding to the chosen merchandise and a photograph filter. Within the closure, you describe the looks of the button. With just a few traces of code, Xcode ought to present you a button within the preview.

For those who click on the button, it shows a Photographs picker for selecting photographs from the picture library. Once you select a photograph, the picture picker mechanically dismisses and the chosen picture merchandise is saved within the selectedItem
variable.

Filtering the Photographs
The matching
parameter allows you to specify the picture filter to use to the picture library. Within the code above, we set its worth to .photographs
to indicate photographs solely. If you wish to show each photographs and movies, set the worth of the parameter to the next:
.any(of: [.images, .videos]) |
The .photographs
filter contains all photographs within the consumer’s picture library. What if you wish to exclude stay pictures from the picture set? You may set the worth like this:
.any(of: [.images, .not(.livePhotos)]) |
You employ the .not
filter to exclude Dwell Photographs.
Dealing with the Picture Choice
As talked about earlier, the chosen picture is mechanically saved within the selectedItem
variable, which has a sort of PhotoPickerItem
. So, how can we load the picture and show it on display?
First, we connect the onChange
modifier to take heed to the replace of the selectedItem
variable. Every time there’s a change, we name the loadTransferable
methodology to load the asset information.
.onChange(of: selectedItem) { newItem in Job { if let information = strive? await newItem?.loadTransferable(kind: Information.self) { selectedPhotoData = information } } } |
Within the WWDC22 session (What’s new within the Photographs picker), Apple’s engineer confirmed us to specify the kind as Picture.self
. That is to instruct loadTransferable
to return an occasion of Picture
. Nevertheless, I couldn’t make it work on Xcode 14 beta 4. That is why I used Information.self
as an alternative. Later, we will convert the info into an UIImage
object for displaying in an Picture
view.
The selectedPhotoData
variable is one other state variable that’s used to carry the info object:
@State personal var selectedPhotoData: Information? |
To show the chosen picture in a picture view, we create an occasion of UIImage
utilizing the picture information after which go it to the Picture
view:
Picture(uiImage: picture)
.resizable()
.scaledToFill()
.clipped()
}
if let selectedPhotoData, let picture = UIImage(information: selectedPhotoData) {
Picture(uiImage: picture) .resizable() .scaledToFill() .clipped()
} |
That is the way you deal with the picture choice. To recap, we retrieve the picture information when a consumer selects a picture from the built-in Photographs library. We save the picture information to a state variable (i.e. selectedPhotoData
). SwiftUI detects the worth change and triggers a UI replace to render the picture on display.

Deciding on A number of Photographs
The PhotosPicker
view also can assist a number of picture choice. Let’s construct one other fast demo to see the way it works. Once more, we have now two state variables to carry the PhotosPickerItem
objects and Information
object. Because the consumer could choose multiple pictures, each variables turn out to be an array:
@State personal var selectedItems: [PhotosPickerItem] = [] @State personal var selectedPhotosData: [Data] = [] |
To assist a number of picture choice, the trick is to make use of one other initialization methodology of PhotosPicker
:
Job {
if let information = strive? await newItem.loadTransferable(kind: Information.self) {
selectedPhotosData.append(information)
}
}
}
}
PhotosPicker(choice: $selectedItems, maxSelectionCount: 5, matching: .photographs) { Picture(systemName: “picture.on.rectangle.angled”) } .onChange(of: selectedItems) { newItems in for newItem in newItems {
Job { if let information = strive? await newItem.loadTransferable(kind: Information.self) { selectedPhotosData.append(information) } }
} } |
This methodology has an extra parameter named maxSelection
. We set the worth to 5
, which implies the consumer is allowed to assist as much as 5 pictures. On this case, we could seize multiple pictures within the onChange
closure. What we did is to load every of the picture gadgets and add it to the info array (i.e. selectedPhotosData
).
For this demo view, as an alternative of making a button on the centre of the display, we put the button within the navigation bar. Right here is the total code snippet:
ScrollView {
VStack {
ForEach(selectedPhotosData, id: .self) { photoData in
if let picture = UIImage(information: photoData) {
Picture(uiImage: picture)
.resizable()
.scaledToFit()
.cornerRadius(10.0)
.padding(.horizontal)
}
}
}
}
.navigationTitle(“Photographs”)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
PhotosPicker(choice: $selectedItems, maxSelectionCount: 5, matching: .photographs) {
Picture(systemName: “picture.on.rectangle.angled”)
}
.onChange(of: selectedItems) { newItems in
for newItem in newItems {
Job {
if let information = strive? await newItem.loadTransferable(kind: Information.self) {
selectedPhotosData.append(information)
}
}
}
}
}
}
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
NavigationStack {
ScrollView { VStack { ForEach(selectedPhotosData, id: .self) { photoData in if let picture = UIImage(information: photoData) { Picture(uiImage: picture) .resizable() .scaledToFit() .cornerRadius(10.0) .padding(.horizontal) } } } }
.navigationTitle(“Photographs”) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { PhotosPicker(choice: $selectedItems, maxSelectionCount: 5, matching: .photographs) { Picture(systemName: “picture.on.rectangle.angled”) } .onChange(of: selectedItems) { newItems in for newItem in newItems {
Job { if let information = strive? await newItem.loadTransferable(kind: Information.self) { selectedPhotosData.append(information) } }
} } } } } |
When there may be any modifications of the selectedPhotosData
variable, SwiftUI will refresh the UI and show the pictures within the scroll view.

For those who get pleasure from this text and wish to dive deeper into SwiftUI, you might try our Mastering SwiftUI e book.