Reputation: 51
I have 2 buttons, one to load an image from the gallery and one to load from the camera (i.e. take photo). But no matter what I try I keep getting gallery load instead of the camera. I've been using the following code (from my google searches) in my UIImagePickerController:
//
// ImagePicker.swift
//
import Foundation
import SwiftUI
class ImagePickerCoordinator: NSObject, UINavigationControllerDelegate,
UIImagePickerControllerDelegate {
@Binding var isShown: Bool
@Binding var image: Image?
init(isShown: Binding<Bool>, image: Binding<Image?>) {
_isShown = isShown
_image = image
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
image = Image(uiImage: uiImage)
isShown = false
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
isShown = false
}
}
struct ImagePicker: UIViewControllerRepresentable {
@Binding var isShown: Bool
@Binding var image: Image?
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
}
func makeCoordinator() -> ImagePickerCoordinator {
return ImagePickerCoordinator(isShown: $isShown, image: $image)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.delegate = context.coordinator
return picker
}
}
struct CameraPicker: UIViewControllerRepresentable {
@Binding var isShown: Bool
@Binding var image: Image?
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<CameraPicker>) {
}
func makeCoordinator() -> ImagePickerCoordinator {
return ImagePickerCoordinator(isShown: $isShown, image: $image)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<CameraPicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.sourceType = .camera
picker.allowsEditing = true
picker.delegate = context.coordinator
return picker
}
}
struct CameraView: UIViewControllerRepresentable {
@Binding var isShown: Bool
@Binding var image: Image?
func makeCoordinator() -> CameraView.Coordinator {
Coordinator(self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<CameraView>) -> UIViewController {
let cameraViewController = UIImagePickerController()
cameraViewController.delegate = context.coordinator
cameraViewController.sourceType = .camera
cameraViewController.allowsEditing = false
return cameraViewController
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<CameraView>) {
}
class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var parent: CameraView
init(_ cameraView: CameraView) {
self.parent = cameraView
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
parent.image = Image(uiImage: uiImage)
parent.isShown = false
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
parent.isShown = false
}
}
}
I basically duplicated the ImagePicker to cater for the camera (CameraPicker). Also tried Camera view from web searches when I couldn't get anywhere.
I'm new to swift so please let me know if there is a better way to do this.
To get image from camera:
//
// PhotoCaptureView.swift
import SwiftUI
struct PhotoCaptureView: View {
@Binding var showImagePicker: Bool
@Binding var image: Image?
var body: some View {
CameraView(isShown: $showImagePicker, image: $image)
}
}
#if DEBUG
struct PhotoCaptureView_Previews: PreviewProvider {
static var previews: some View {
PhotoCaptureView(showImagePicker: .constant(false), image: .constant(Image("")))
}
}
#endif
To get image from gallery:
//
// GalleryCapture.swift
//
import SwiftUI
struct GalleryCaptureView: View {
@Binding var showImagePicker: Bool
@Binding var image: Image?
var body: some View {
ImagePicker(isShown: $showImagePicker, image: $image)
}
}
#if DEBUG
struct GalleryCaptureView_Previews: PreviewProvider {
static var previews: some View {
GalleryCaptureView(showImagePicker: .constant(false), image: .constant(Image("")))
}
}
#endif
My contentview:
//
// ContentView.swift
//
import SwiftUI
struct ContentView: View {
@State private var showImagePicker: Bool = false
@State private var image: Image? = nil
// Function that converts an UIImage to Image
func returnImage() -> Image
{
guard let img = image else {
fatalError("Unable to load image")
}
return img
// return Image(uiImage: img)
}
// Main Body
var body: some View {
NavigationView {
VStack {
VStack {
image?.resizable()
.frame(width: 299, height: 299)
.cornerRadius(6)
}
// returnImage()
// .resizable()
// .frame(width: 299, height: 299)
// .cornerRadius(6)
// .onTapGesture {
// self.showImagePicker = true
// }
HStack {
Button(action: {self.showImagePicker.toggle()}) {
Image(systemName: "photo")
.font(.largeTitle)
.foregroundColor(.white)
Text("Gallery")
.foregroundColor(.white)
}.padding()
.background(Color.blue)
.cornerRadius(10)
.sheet(isPresented: self.$showImagePicker) {
GalleryCaptureView(showImagePicker: self.$showImagePicker, image: self.$image)
}
Button(action: {self.showImagePicker.toggle()}) {
Image(systemName: "camera")
.font(.largeTitle)
.foregroundColor(.white)
Text("Camera")
.foregroundColor(.white)
}.padding()
.background(Color.green)
.cornerRadius(10)
.sheet(isPresented: self.$showImagePicker) {
PhotoCaptureView(showImagePicker: self.$showImagePicker, image: self.$image)
}
}
}
.navigationBarTitle("My first app")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I want to use MLkit so probably need to look at using UIImage instead of Image as well.
Upvotes: 1
Views: 1459
Reputation: 51
Turned out to be so simple in the end. My mistake was to use the same boolean as the one I used for gallery.
Upvotes: 2
Reputation: 594
on button you have to self.showImagePicker to true like this :
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"))
}
}
inside the makeUIViewController method, you just need to add the following code right below picker.delegate = context.coordinator:
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.delegate = context.coordinator
if !UIImagePickerController.isSourceTypeAvailable(.camera){
picker.sourceType = .photoLibrary
} else {
picker.sourceType = .camera
}
return picker
}
Note : Camera opens only in real device you cant open in simulator.
OR
compare ur code with this awesome code , its working from my side
Upvotes: 1