Mastering SwiftUI's PhotoPicker: A Comprehensive Guide
Written on
Introduction to PhotoPicker
In today’s app development landscape, visuals carry immense weight, making the ability to incorporate images a powerful asset. Whether your app is a social platform, a creative space, or simply allows users to personalize their experience, enabling image selection can significantly enhance user interaction. The PhotoPicker, known for its straightforwardness, is essential for nearly all contemporary applications.
When a PhotoPicker is initiated, it overlays the user’s photo library, prompting them to choose one or multiple images for use within the app. With the release of iOS 16, Apple introduced new customization options for the PhotoPicker, which we'll explore further along in this guide.
Let's dive into the two primary methods for implementing a PhotoPicker in SwiftUI, focusing on the latest approach introduced in iOS 16 compared to the traditional method.
Traditional Implementation
To begin with the classic approach, we’ll set up a ViewController to present the user’s photo library. We need to specify whether we want to select images from the library or the camera by setting the sourceType. Additionally, we’ll create a Coordinator and a selectedImage variable to preview the chosen image in the View.
import SwiftUI
struct PhotoPicker: UIViewControllerRepresentable {
@Environment(.presentationMode) private var presentationMode
var sourceType: UIImagePickerController.SourceType = .photoLibrary
@Binding var selectedImage: UIImage
func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIImagePickerController {
let photoPicker = UIImagePickerController()
photoPicker.allowsEditing = false
photoPicker.sourceType = sourceType
photoPicker.delegate = context.coordinator
return photoPicker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext) {}
func makeCoordinator() -> Coordinator {
Coordinator(self)}
final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var parent: PhotoPicker
init(_ parent: PhotoPicker) {
self.parent = parent}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
parent.selectedImage = image}
parent.presentationMode.wrappedValue.dismiss()
}
}
}
Note: By default, the selection is limited to images only, excluding videos.
Adding State Variables
To integrate the PhotoPicker within SwiftUI, we must establish two state variables: one to track the visibility of the PhotoPicker and another to store the selected image.
@State private var selectedImage = UIImage()
@State private var isShowingPhotoPicker = false
In our example application, we’ll create a view that displays the image and a button to open the PhotoPicker.
var profileImage: Image {
selectedImage == UIImage() ? Image(systemName: "person.circle") : Image(uiImage: selectedImage)
}
var body: some View {
HStack {
profileImage
.resizable()
.cornerRadius(25)
.frame(width: 50, height: 50)
.background(Color.black.opacity(0.2))
.aspectRatio(contentMode: .fill)
.clipShape(Circle())
Button {
isShowingPhotoPicker = true} label: {
Label("Select Photo", systemImage: "photo")}
}
.sheet(isPresented: $isShowingPhotoPicker) {
PhotoPicker(sourceType: .photoLibrary, selectedImage: self.$selectedImage)}
}
Finally, we need to add a sheet modifier to our main view to display the PhotoPicker when the button is clicked:
.sheet(isPresented: $isShowingPhotoPicker) {
PhotoPicker(sourceType: .photoLibrary, selectedImage: self.$selectedImage)
}
To use the camera instead, simply change the sourceType to .camera. Remember to update your Info.plist to include a key for requesting camera access, labeled as Privacy — Camera Usage Description.
The iOS 16 Solution
With iOS 16, Apple unveiled the PhotosUI framework, allowing for native PhotoPicker integration within SwiftUI. Let’s examine how to utilize this feature.
Start by establishing the following state variables:
@State private var selectedItem: PhotosPickerItem?
@State private var selectedImageData: Data? = nil
For improved memory management, the PhotoPicker returns a PhotoPickerItem, which we can later use to access the underlying asset.
Next, let’s define our view layout again:
var profileImage: Image {
guard let data = selectedImageData,
let image = UIImage(data: data) else {return Image(systemName: "person.circle")
}
return Image(uiImage: image)
}
var body: some View {
HStack {
profileImage
.resizable()
.cornerRadius(25)
.frame(width: 50, height: 50)
.background(Color.black.opacity(0.2))
.aspectRatio(contentMode: .fill)
.clipShape(Circle())
PhotosPicker(
selection: $selectedItem,
matching: .images,
photoLibrary: .()) {
Label("Select Photo", systemImage: "photo")}
}
.onChange(of: selectedItem) { newItem in
Task {
// Retrieve selected asset in the form of Data
if let data = try? await newItem?.loadTransferable(type: Data.self) {
selectedImageData = data}
}
}
}
This layout mirrors the previous implementation while leveraging PhotoPickerItem for selecting images of various formats through PHPickerFilter. You can also specify a particular photo library for your selections. For more detailed information, consider reviewing the PHPhotoLibrary section in Apple’s documentation.
To convert the PhotoPickerItem to Data, we’ll use the onChange() modifier for detecting changes in the selected item:
.onChange(of: selectedItem) { newItem in
Task {
// Retrieve selected asset in the form of Data
if let data = try? await newItem?.loadTransferable(type: Data.self) {
selectedImageData = data}
}
}
Conclusion
The SwiftUI PhotoPicker allows developers to seamlessly integrate image selection, enhancing user engagement without relying on text. This guide has explored both the traditional method and the new iOS 16 approach, illustrating the flexibility and power of the PhotoPicker. Whether you choose to stick with the familiar technique or embrace the latest innovation, the PhotoPicker is an invaluable asset in your SwiftUI toolkit.
This video covers the use of PhotosPicker in SwiftUI and highlights the benefits of utilizing Swift Concurrency for a more efficient implementation.
This video demonstrates the new SwiftUI Photo Picker, featuring both single and multiple image selections, showcasing its versatility.
Final Thoughts
Thank you for reading! I hope you found this guide informative. If you’re interested in more content, feel free to check out my website for updates.
Lastly, a special mention to my sponsor, Surfshark. If you’re in need of a reliable VPN solution, Surfshark provides fast speeds, strong security, and global coverage, making it an excellent choice for safeguarding your online privacy and accessing your favorite content worldwide. Their user-friendly applications make setup a breeze, and their competitive pricing ensures accessibility for all. Try Surfshark and experience the benefits for yourself!