Implement an ImagePicker in SwiftUI

Choose from your library or take a photo, all in SwiftUI

Mayur Rathod
Better Programming

--

Step 1. How To Create Your SwiftUI Project

In Xcode, go to File → New → Project → Single View App → Next → Select User Interface → SwiftUI → Next → Select your desired project location → Done.

Step 2. ContentView.swift

The default SwiftUI(ContentView) file will come up with the following code:

import SwiftUI
struct ContentView: View {var body: some View {
Text(”Hello World!”)
}
}struct ContentView_Previews: PreviewProvider {
static
var previews: some View {
ContentView()
}
}

On the right-hand side, you can see the preview of the UI.

If you’re not able to see the preview, go to the Adjust Editor option, and select Canvas (or press option+CMD+enter). After that, make sure the canvas is showing the UI preview.

Step 3. Creating a User Interface

Inside the ContentView body we will be doing the following things:

  1. Define the NavigationView and give the navigationBarTitle.
  2. Define the VStack.
  3. Inside VStack, we have to define an Image where we will display the selected image and a Button. By clicking on this button, we will open up the ImagePicker.

So, our code will look something like this:

import SwiftUIstruct Demo: View {
var body: some View {
//MARK: Step 1: Define the NavigationView and give the navigationBarTitle

NavigationView{
//MARK: Step 2: Define the VStack
VStack {
//MARK: Define the Image
Image(systemName: “cloud”)
.resizable()
.scaledToFit()
.padding()
.foregroundColor(Color.orange)

//MARK: Define the Button
Button(“Open Camera”){
//Button Action Goes here
}.padding()
.foregroundColor(Color.white)
.background(Color.orange)
.cornerRadius(10)
}
.navigationBarTitle(Text(“Camera”))
}
}
}
struct Demo_Previews: PreviewProvider {
static var previews: some View {
Demo()
}
}

Now we are done with our UI. Next, we have to implement the UIImagePickerController.

Step 4. Creating a UIImagePickerController

Now the question is: “How are you going to show a UIImagePickerController?” So, to display a UIImagePickerController, we are going to use the UIViewControllerRepresentable protocol.

struct ImagePicker : UIViewControllerRepresentable {}

Now, we have to implement the protocol methods, which are updateUIViewController, makeCoordinator, and makeUIViewController.

func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) 
{
//Update UIViewcontrolleer Method
}
func makeCoordinator(){//Make Coordinator which will commnicate with the ImagePickerViewController
}
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>)
{
// Create UIViewController which we will display inside the View of the UIViewControllerRepresentable
}

Since we have implemented all the methods of the protocol UIViewControllerRepresentable, let’s create an ImagePickerViewController inside the makeUIViewController method.

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

Step 5. Creating an ImagePickerCordinator

Now we have to create a coordinator that can communicate between the UIViewControllerRepresentable and the ImagePickerViewController delegate methods.

So, we will create a new class, ImagePickerCordinator, that will implement the protocol UINavigationControllerDelegate and UIImagePickerControllerDelegate, and will implement the methods required by these protocols.

The ImagePickerCordinator will look something like this:

class ImagePickerCordinator : NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate{var image      : Image?//Selected Image
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
image = Image(uiImage: uiImage)

}
//Image selection got cancel
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {

}
}

Now, if the user selects an image, we have to notify our ContentView to show the selected image.

For that, we will use the concept of the @Bindingand @State. We will create two Binding variables named image and isShown, so now our ImagePickerCordinator will look like this:

class ImagePickerCordinator : NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate{@Binding var isShown : Bool
@Binding var image : Image?
init(isShown : Binding<Bool>, image: Binding<Image?>) {
_isShown = isShown
_image = image
}
//Selected Image
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImageimage = Image(uiImage: uiImage)
isShown = false
}//Image selection got cancel
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
isShown = false
}
}

Now that our coordinator is ready to communicate, let’s make the changes into the UIViewControllerRepresentable makeCoordinator() function.

func makeCoordinator() -> ImagePickerCordinator {
return ImagePickerCordinator(isShown: $isShown, image: $image)
}

To pass the binding variables in ImagePickerCordinator, we will create these two variables in the UIViewControllerRepresentable. Now the UIViewControllerRepresentable file will look something like this:

struct ImagePicker : UIViewControllerRepresentable {   @Binding var isShown : Bool
@Binding var image : Image?
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {}func makeCoordinator() -> ImagePickerCordinator {
return ImagePickerCordinator(isShown: $isShown, image: $image)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {let picker = UIImagePickerController()
picker.delegate = context.coordinator
return picker
}
}

Step 6. Creating a PhotoCaptureView

Whenever the user clicks on the Button in the ContentView, we want to display an imagePicker inside the sheet or modal.

For that, we will have to create a new CustomView, which we can name PhotoCaptureView, which will be calling the ImagePicker. It is a UIViewControllerRepresentable so it will look something like this:

import SwiftUIstruct PhotoCaptureView: View {   @Binding var showImagePicker : Bool
@Binding var image : Image?

var body: some View {
ImagePicker(isShown: $showImagePicker, image: $image)
}
}
struct PhotoCaptureView_Previews: PreviewProvider {
static var previews: some View {
PhotoCaptureView(showImagePicker: .constant(false), image: .constant(Image(“”)))
}
}

Final Step 7. Implement ImagePicker in ContentView

Inside the contentView, we just have to create two @State variables, named showImagePicker and image. This will create a sheet or modal and calls the CustomView, i.e. PhotoCaptureView, so our ContentView code will look like this:

import SwiftUIstruct ContentView: View {
@State private var showImagePicker : Bool = false
@State private var image : Image? = nil

var
body: some View {
NavigationView{
VStack {
image?.resizable().scaledToFit()
Button(“Open Camera”){
self.showImagePicker = true
}.padding()
.foregroundColor(Color.white)
.background(Color.purple)
.cornerRadius(10)
}.sheet(isPresented: self.$showImagePicker)
{
PhotoCaptureView(showImagePicker: self.$showImagePicker, image: self.$image)
}
.navigationBarTitle(Text(“Camera”))
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

Final Product

The final code will look like this:

Find this project on GitHub.

--

--