Swift UI Camera and Photo Library Access in SwiftUI: With Permission

Camera and Photo Library Access in SwiftUI: With Permission

Building an app that requires seamless integration with the device’s camera or photo library? You’re at the right place! With over a decade of experience in iOS development, I understand the intricacies of blending SwiftUI with UIKit, ensuring a robust and user-friendly outcome. This guide will offer you a detailed walkthrough.

Preliminary Step: Securing User Permissions

Any access to sensitive areas like the camera or photo library mandates user permission. As a transparent and ethical developer, always provide clear reasons for this access.

Incorporate these lines in your Info.plist:

<key>NSCameraUsageDescription</key>
<string>We need access to the camera to take photos.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need access to the photo library to choose photos.</string>

The Heart of the App: The ContentView

Start with the ContentView—your primary interface canvas:

struct ContentView: View {
    @State private var image: UIImage?
    @State private var showingImagePicker = false
    @State private var sourceType: UIImagePickerController.SourceType = .photoLibrary

    var body: some View {
        VStack {
            if let img = image {
                Image(uiImage: img)
                    .resizable()
                    .scaledToFit()
            }

            Button("Choose Photo") {
                self.sourceType = .photoLibrary
                self.showingImagePicker = true
            }
            .padding()

            Button("Take Photo") {
                self.sourceType = .camera
                self.showingImagePicker = true
            }
            .padding()
            .disabled(!UIImagePickerController.isSourceTypeAvailable(.camera))
        }
        .sheet(isPresented: $showingImagePicker) {
            ImagePicker(image: self.$image, sourceType: self.sourceType)
        }
    }
}

Embed within it a few state variables:

  • image: Holds the chosen/captured image.
  • showingImagePicker: Toggles the image picker’s visibility.
  • sourceType: Defines the image source – camera or library.
    @State private var image: UIImage?
    @State private var showingImagePicker = false
    @State private var sourceType: UIImagePickerController.SourceType = .photoLibrary

Dive into the body:

    var body: some View {
        VStack {
            ...
        }
    }

The VStack neatly organizes your UI elements. When an image exists, it gets displayed flawlessly:

            if let img = image {
                Image(uiImage: img)
                    .resizable()
                    .scaledToFit()
            }

Lastly, those interactive buttons:

            Button("Choose Photo") {
                ...
            }
            Button("Take Photo") {
                ...
            }

Users can select an image or capture a new one. A savvy use of .disabled keeps users informed on devices without camera capability.

Bridging the Gap: The ImagePicker

SwiftUI, though splendid, occasionally requires UIKit’s seasoned capabilities. This is where UIViewControllerRepresentable shines:

struct ImagePicker: UIViewControllerRepresentable {
    @Binding var image: UIImage?
    @Environment(\.presentationMode) var presentationMode
    let sourceType: UIImagePickerController.SourceType

    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.delegate = context.coordinator
        picker.sourceType = sourceType
        return picker
    }

    func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
        let parent: ImagePicker

        init(_ parent: ImagePicker) {
            self.parent = parent
        }

        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            if let uiImage = info[.originalImage] as? UIImage {
                parent.image = uiImage
            }

            parent.presentationMode.wrappedValue.dismiss()
        }

        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            parent.presentationMode.wrappedValue.dismiss()
        }
    }
}

Crucial properties inside:

  • image: Binds with ContentView‘s image.
  • presentationMode: Enables self-dismissal.
  • sourceType: Specifies the image source.

Venturing deeper, the ImagePicker structures the appearance and interaction:

    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.delegate = context.coordinator
        picker.sourceType = sourceType
        return picker
    }

    func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

The Coordinator is pivotal, orchestrating events and interactions:

    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
        let parent: ImagePicker

        init(_ parent: ImagePicker) {
            self.parent = parent
        }

        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo       info: [UIImagePickerController.InfoKey : Any]) {
            if let uiImage = info[.originalImage] as? UIImage {
                parent.image = uiImage
            }

            parent.presentationMode.wrappedValue.dismiss()
        }

        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            parent.presentationMode.wrappedValue.dismiss()
        }
    }

It manages the image picker’s feedback, and ensures the seamless integration between SwiftUI and UIKit.

Summary

Combining the camera and photo library in SwiftUI requires finesse, a dash of UIKit, and an unwavering commitment to user trust. By ensuring transparent permissions and smooth integration, you offer users an app experience par excellence.

Leave a Reply

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

Related Post