thecanteen
thecanteen

Reputation: 784

Calling Method on Child View in SwiftUI

I have an ImageEditView that contains an ImageCanvasView and an ImageCaptureButton.

Ideally, I want ImageCaptureButton to call a method on ImageCanvasView called takeScreenshot.

How do I achieve this in SwiftUI? I've been thinking of trying to save ImageCanvasView into a variable in ImageEditView so that my ImageCaptureButton can then call its method, but SwiftUI's declarative nature means this isn't possible.

----- EDIT below -----

The flow is as follows:

  1. ImageSelectView (user selects an image)
  2. ImageEditView (user edits an image) - this view contains ImageCanvasView and ImageCaptureButton
  3. ImageShareView (user shares the image)

The following is ImageEditView

import SwiftUI

struct ImageEditView: View {
    
    @State var selectedImage: Image
    
    @State private var isNavLinkPresented = false
    @State private var imageSnapshot: UIImage = UIImage()
    
    var canvasView: ImageCanvasView = ImageCanvasView(selectedImage: $selectedImage) 
    // this won't work: Cannot use instance member '$selectedImage' within property initializer; property initializers run before 'self' is available
        
    var body: some View {

            VStack {
                canvasView
                Spacer()
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    NavigationLink(destination: ImageShareView(imageToShare: $imageSnapshot), isActive: $isNavLinkPresented) {
                        Text("Next")
                            .onTapGesture {
                                imageSnapshot = canvasView.takeScreenshot()
                                isNavLinkPresented = true
                            }
                    }
                    
                }
                
            }
            .navigationBarTitle(Text("Edit image"))
        
    }
    
}

Upvotes: 0

Views: 2372

Answers (1)

Raja Kishan
Raja Kishan

Reputation: 18894

You are in the right direction. By creating var of the view, you can call the function. Here is the example demo

struct ImageEditView: View {
    
    var canvasView: ImageCanvasView = ImageCanvasView()
    
    var body: some View {
        VStack {
            Text("ImageEditView")
            canvasView
            Button("ImageCaptureButton") {
                canvasView.takeScreenshot()
            }
        }
    }
}

struct ImageCanvasView: View {
    var body: some View {
        Text("ImageCanvasView")
    }
    
    func takeScreenshot() {
        print(#function + " Tapped ")
    }
}

You can also use computed property to pass data

struct ImageEditView: View {
    var data: String = ""
    var canvasView: ImageCanvasView {
        ImageCanvasView(data: data)
    }
    
   // Body code
}

struct ImageCanvasView: View {
    var data: String
    
    var body: some View {
        Text("ImageCanvasView")
    }
    
    func takeScreenshot() {
        print(#function + " Tapped ")
    }
}

EDIT Use init to use the same instance of ImageCanvasView.

struct ImageEditView: View {
    
    @State var selectedImage: Image
    
    @State private var isNavLinkPresented = false
    @State private var imageSnapshot: UIImage = UIImage()
    
    var canvasView: ImageCanvasView!

    init(selectedImage: Image) {
        self.selectedImage = selectedImage
        canvasView = ImageCanvasView(selectedImage: $selectedImage)
    }
    // Other code

Upvotes: 2

Related Questions