Search code examples
swiftswiftuiswiftui-ontapgesture

SwiftUI - modifiying variable foreach on View before onTapGesture()


Foreach on view must be presented with a View to process.

struct Home : View {

  private var numberOfImages = 3
  @State  var isPresented : Bool = false  
  @State  var currentImage : String = ""

  var body: some View {
    VStack {
      TabView {
        ForEach(1..<numberOfImages+1, id: \.self) { num in
    
        Image("someimage")
            .resizable()
            .scaledToFill()
            .onTapGesture() {
                currentImage = "top_00\(num)"
                isPresented.toggle()
            }
        }
    }.fullScreenCover(isPresented: $isPresented, content: {FullScreenModalView(imageName: currentImage) } )
  }
}

I'm trying to display an image in fullScreenCover. My problem is that the first image is empty. Yes, we can solve this defining at the beginning, however, this will complicate the code according to my experiences.

My question is, is it possible to assign a value to currentImage before the onTapGesture processed.

In short, what is the good practice here.


Solution

  • What you need is to use this modifier to present your full screen modal:

    func fullScreenCover<Item, Content>(item: Binding<Item?>, onDismiss: (() -> Void)? = nil, content: @escaping (Item) -> Content) -> some View where Item : Identifiable, Content : View
    

    You pass in a binding to an optional and uses the non optional value to construct a destination:

    struct ContentView: View {
        
        private let imageNames = ["globe.americas.fill", "globe.europe.africa.fill", "globe.asia.australia.fill"]
        @State var selectedImage: String?
        
        var body: some View {
            VStack {
                TabView {
                    ForEach(imageNames, id: \.self) { imageName in
                        Image(systemName: imageName)
                            .resizable()
                            .scaledToFit()
                            .padding()
                            .onTapGesture() {
                                selectedImage = imageName
                               
                            }
                    }
                }
                .tabViewStyle(.page(indexDisplayMode: .automatic))
                .fullScreenCover(item: $selectedImage) { imageName in
                    Destination(imageName: imageName)
                }
            }
        }
    }
    
    struct Destination: View {
        
        let imageName: String
        
        var body: some View {
            ZStack {
                Color.blue
                Image(
                    systemName: imageName
                )
                .resizable()
                .scaledToFit()
                .foregroundColor(.green)
            }
            .edgesIgnoringSafeArea(.all)
        }
    }
    

    You will have to make String identifiable for this example to work (not recommended):

    extension String: Identifiable {
        public var id: String { self }
    }