0

I have build a ZStack containing an image, an overlay and a systemImage. I want to open a sheet when the user taps on this image but it only works when the user clicks on a very specific point on the very bottom of the ZStack. Does anyone know how I can make this work? And also why this doesn't work? My code:

NavigationView {
        VStack {
            VStack {
                ZStack {
                    if let image = pfimage {
                        Image (uiImage: image)
                            .resizable()
                            .frame(width: 100, height: 100)
                    } else {
                        Image ("testimage")
                            .resizable()
                            .frame(width: 100, height: 100)
                    }
                    Image(systemName: "photo")
                        .resizable()
                        .frame(width: 30, height: 25)
                        .foregroundColor(Color.white)
                    
                }
                .clipShape(Circle())
                .contentShape(Circle())
                .onTapGesture {
                    print("tap")
                    changepfsheet = true
                }
                
                Text("Displayname")
                    .padding(.top)
                    .foregroundColor(Color.white)
                    .font(.title3)
            }
            .frame(width: UIScreen.main.bounds.width, height: 225)
            .background(Color.red)
            
            HStack {
                Image(systemName: "person.2.circle")
                
                TextField("Enter newdisplayname", text: $newdisplayname)

            }
            .padding()
            .background(Color.gray.opacity(0.1))
            .cornerRadius(10)
            .padding(.horizontal)
            .padding(.top, 25)
                  
            Text("Change displayname")
            

            
            Spacer()
            

            HStack {

                Spacer()
                Text("Change password")
                    .foregroundColor(Color.white)
                Spacer()
                Image(systemName: "key")
                    .foregroundColor(Color.white)
            }
            .padding()
            .background(Color.red)
            .cornerRadius(15)
            .padding(.horizontal)
            .padding(.bottom, 5)
            
            HStack {
                Spacer()
                Text("Logout")
                Spacer()
            }
            .padding(.horizontal)
            .padding(.bottom, 20)
        }
        .edgesIgnoringSafeArea(.top)
        Spacer()
    }
    .navigationBarHidden(false)
    .navigationBarBackButtonHidden(false)
chrispsv
  • 503
  • 1
  • 3
  • 21

1 Answers1

1

You have interfering tap gestures. Instead, just have one tap gesture on the ZStack. Now you can tap anywhere on it:

ZStack {
    Image(uiImage: image)
        .resizable()
        .frame(width: 100, height: 100)

    Color.black.opacity(0.5)
        .frame(width: 100, height: 100)

    Image(systemName: "photo")
        .resizable()
        .frame(width: 30, height: 25)
        .foregroundColor(.white)
}
.clipShape(Circle())
.contentShape(Circle())
.onTapGesture {
    print("tap")
    showsheet = true
}

I suspect the real issue is that you using a NavigationView, and putting content behind where the title would be. That means that you can't click through the view that the title is in, even if it's an empty title. You should either remove the NavigationView (as you aren't making use of it) or don't ignore safe area and use a NavigationView as you should do.

Removing edgesIgnoringSafeArea(.top) makes your code work, because the content will no longer be behind the navigation bar.

George
  • 25,988
  • 10
  • 79
  • 133
  • Thanks for your answer. I have tried that but now nothing of the entire ZStack is tap-able. That's why I added an onTapGesture on everything in the ZStack to make it tab-able on only a small part of the ZStack – chrispsv Aug 12 '21 at 10:21
  • @chrispsv That could be due to other factors, not mentioned in the question. If you run this in `ContentView` of a blank app, with your `showsheet` state variable and `image`, it now works. Is it still printing "tap", even if the sheet is showing? – George Aug 12 '21 at 10:29
  • Its not printing tap. So the showsheet is also not opening. But I have made a new swiftui file and if I only run this code then it works. What other factors could cause this problem? – chrispsv Aug 12 '21 at 10:36
  • @chrispsv Given that you said _part_ of it works, maybe some other overlay/ZStack with a view? This view would then 'absorb' the taps, and it would not go to this lower view. If you have an overlapping view, use `allowsHitTesting(false)` on it. It's quite hard to debug though without having any idea what your views look like. Also, thinking about it - all those tap gestures you have would work in the original question because they all run the same code, it's just redundant to have so many when you only need one on the outer ZStack. – George Aug 12 '21 at 10:44
  • I have deleted all the other OnTapGestures (I added them just to see if it worked but I know I shouldn't need so many) and added the allowsHitTesting. It didn't change anything. I have added the entire struct to the question. – chrispsv Aug 12 '21 at 11:00
  • @chrispsv Your amended code is working fine if you remove the `allowsHitTesting(false)` modifier. Use that on a view where itself or any 'sub-views' should ignore touches. Placing that modifier is disabling all touches for the tap gesture. – George Aug 12 '21 at 12:02
  • I removed the .allowsHitTesting. But it still doesn't work. However if I change the position of the ZStack then it works. So it has something to do with the position of the ZStack – chrispsv Aug 12 '21 at 12:36
  • @chrispsv Even with the updated code, it still works. So I can't really debug more than that. We need a minimal, reproducible example – George Aug 12 '21 at 12:37
  • I have now removed as much as I could in the code. I hope this is enough. Thank you very much for your help. I have already spend 2 hours looking for the problem. – chrispsv Aug 12 '21 at 12:48
  • @chrispsv Removing `.edgesIgnoringSafeArea(.top)` fixes it, but that's probably not the layout you want. It is a very odd issue. If you play around with the ignoring safe area modifier and the `Spacer()`s you can fix it. It does change the layout though – George Aug 12 '21 at 13:09
  • @chrispsv I suspect the real issue is that you using a `NavigationView`, and putting content _behind_ where the title would be. That means that you can't click through the view that the title is in, even if it's an empty title. You should either remove the `NavigationView` (as you aren't making use of it) or don't ignore safe area and use a `NavigationView` as you should do – George Aug 12 '21 at 13:12
  • I just found the solution at the same time you did haha. Thank you very much for all the time you put in everyones (and of course mine) issues. – chrispsv Aug 12 '21 at 13:15
  • @chrispsv Added a small summary of these comments to answer. If you found this useful, an upvote & accept would be appreciated! – George Aug 12 '21 at 13:18