Search code examples
iosswiftxcodeswiftuiuikit

how to pass an img value between 2 views?


I am trying to pass a @Binding UI Image from an Image picker to another view through a sheet. I tried to use the OnDismiss() parameter but it did not work, even tried ondisapper(). What i want is that, when i press a button, it should open up the image picker directly. When a user has selected an image it should take that image and navigate to another view and show the image. This is the code im trying but is not working : -

NavigationBar.swift

import SwiftUI

struct NavigationBar: View {
    var title = ""
    @Binding var hasScrolled: Bool
    @State var showUploadPost = false
    @State var imagePickerPresented = false
    @State private var selectedImage: UIImage?
    @State var postImage: Image?
//    @State var showAccount = false
    @State var captionText = ""
    
    var body: some View {
        ZStack {
            Color.clear
                .background(.ultraThinMaterial)
                .blur(radius: 10)
                .opacity(hasScrolled ? 1 : 0)
            
            Text(title)
                .animatableFont(size: hasScrolled ? 22 : 34, weight: .bold)
                .frame(maxWidth: .infinity, alignment: .leading)
                .padding(.leading, 20)
                .padding(.top, 20)
                .offset(y: hasScrolled ? -4 : 0)
            
            HStack(spacing: 16) {
                Button {
                    imagePickerPresented = true
                } label: {
                    Image(systemName: "plus.square")
                        .font(.title3.weight(.bold))
                        .frame(width: 46, height: 46)
                        .foregroundColor(.secondary)
                        .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 14, style: .continuous))
                    .strokeStyle(cornerRadius: 14)
                }
               .sheet(isPresented: $imagePickerPresented, onDismiss: {
                    newPostView(image: $selectedImage) // this is the problem
                }) {
                    ImagePicker(image: $selectedImage)
                } 
                
            .frame(maxWidth: .infinity, alignment: .trailing)
            .padding(.trailing, 20)
            .padding(.top, 20)
            .offset(y: hasScrolled ? -4 : 0)
        }
        .frame(height: hasScrolled ? 44 : 70)
        .frame(maxHeight: .infinity, alignment: .top)
    }
}

extension NavigationBar {
    func loadImage() {
        guard let selectedImage = selectedImage else { return }
        postImage = Image(uiImage: selectedImage)
    }
}

newPostView.swift

import SwiftUI

struct newPostView: View {
    @Binding var image: UIImage?
    
    var body: some View {
        VStack {
            Text("hi")
        }
    }
}

ImagePicker.swift


struct ImagePicker: UIViewControllerRepresentable {
    @Binding var image: UIImage?
    @Environment(\.presentationMode) var mode
    
    func makeUIViewController(context: Context) -> some UIViewController {
        let picker = UIImagePickerController()
        picker.delegate = context.coordinator
        return picker
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        
    }
    
    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
        let parent: ImagePicker
        
        init(_ parent: ImagePicker) {
            self.parent = parent
        }
        
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            guard let image = info[.originalImage] as? UIImage else { return }
            self.parent.image = image
            self.parent.mode.wrappedValue.dismiss()
        }
    }
}

Solution

  • Solution 1: Simply use hidden navigation bar technique to push it to another view on selecting the Image.

    struct NavigationBar: View {
        @State var imagePickerPresented = false
        @State private var selectedImage: UIImage?
        @State private var newPost = false
    
        var body: some View {
            VStack {
                Text("Hello, World!")
                Button {
                    imagePickerPresented = true
                } label: {
                    Image(systemName: "plus.square")
                        .font(.title3.weight(.bold))
                        .frame(width: 46, height: 46)
                        .foregroundColor(.secondary)
                        .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 14, style: .continuous))
                }
                .sheet(isPresented: $imagePickerPresented, onDismiss: {
                    newPost.toggle() //1 <--- FIX
                }) {
                    ImagePicker(image: $selectedImage)
                }
                
                // 2 FIX ⬇️
                // Hide Navigation Link
                NavigationLink("NewPostView", isActive: $newPost) {
                    newPostView(image: $selectedImage)
                }.hidden()
            }
        }
    }
    

    Note: This works when the NavigationBar is inside the NavigationView. For example -

    struct ContenView: View {
        var body: some View {
            NavigationView{
                NavigationBar()
            }
        }
    }
    

    Solution 2: If you don't want Navigation to the newPostView, use like this

    struct NavigationBar: View {
        @State var imagePickerPresented = false
        @State private var selectedImage: UIImage?
        @State private var newPost = false
    
        var body: some View {
            VStack {
                Text("Hello, World!")
                Button {
                    imagePickerPresented = true
                } label: {
                    Image(systemName: "plus.square")
                        .font(.title3.weight(.bold))
                        .frame(width: 46, height: 46)
                        .foregroundColor(.secondary)
                        .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 14, style: .continuous))
                }
                .sheet(isPresented: $imagePickerPresented, onDismiss: {
                    newPost.toggle() //1 <--- FIX
                }) {
                    ImagePicker(image: $selectedImage)
                }
                .fullScreenCover(
                  isPresented: $newPost) {
                      newPostView(image: $selectedImage)
                }
            }
        }
    }
    
    struct ContentView: View {
        @State var imagePickerPresented = false
        @State private var selectedImage: UIImage?
        @State private var newPost = false
        
        var body: some View {
            NavigationBar()
        }
    }