SwiftUI Blog

Mastering SwiftUI: Your Guide to Building Beautiful, Intuitive Apps.

Select Photos from the gallery

In SwiftUI, it’s possible to select a photo (or multiple photos) from the gallery and use them in an application. The main component for this is PhotosPicker. When a photo is selected, it’s stored in a PhotosPickerItem.

It’s also possible to select videos, not just photos. We can specify the type of media to display in the gallery, such as screenshots, panoramas, or videos. It’s also possible to exclude certain types of media using the .not notation, for example: matching: .not(.videos).

Take a look at the code:

import SwiftUI
import PhotosUI

struct ContentView: View {
    @State private var photoItem: PhotosPickerItem?
    @State private var photoImage: Image?

    var body: some View {
        VStack {
            PhotosPicker("Select photo", selection: $photoItem, matching: .images)

            photoImage?
                .resizable()
                .scaledToFit()
        }
        .onChange(of: photoItem) {
            Task {
                if let loaded = try? await photoItem?.loadTransferable(type: Image.self) {
                    photoImage = loaded
                } else {
                    print("Some problem loading the photo")
                }
            }
        }
    }
}


In the code, we configure the PhotosPicker to display all images. When an image is selected, it’s loaded and assigned to the local photoImage variable inside the task.

It’s also possible to select multiple items; in that case, both photoItem and photoImage must be arrays.

Take a look at the code:

import SwiftUI
import PhotosUI

struct ContentView: View {
    @State private var selectedItems = [PhotosPickerItem]()
    @State private var selectedPhotos = [Image]()

    var body: some View {
        VStack {
            PhotosPicker("Select images", selection: $selectedItems, matching: .any(of: [.images, .not(.screenshots)]))
            ScrollView {
                LazyVStack {
                    ForEach(0..<selectedPhotos.count, id: \.self) { i in
                        selectedPhotos[i]
                            .resizable()
                            .scaledToFit()
                            .frame(width: 300, height: 300)
                    }
                }
            }
            .onChange(of: selectedItems) {
                Task {
                    selectedPhotos.removeAll()
                    
                    for item in selectedItems {
                        if let image = try? await item.loadTransferable(type: Image.self) {
                            selectedPhotos.append(image)
                        }
                    }
                }
            }
        }
    }
}

Note how is defined the match: matching: .any(of: [.images, .not(.screenshots)])

We can select every images but not screenshots.

Leave a Reply

Your email address will not be published. Required fields are marked *