0

Thanks to a previous question I asked, I am using Color.black.overlay and .clipped() to show an image with letterbox borders above and below it.

But when I attempt to put a button on the top border, it can't be tapped on (I assume because the image (unclipped) is in that space, and is intercepting the tap gesture).

Here is what the layout looks like:

enter image description here

Here is the code:

    var body: some View {
        ZStack {
            Color.black
            VStack {
                topBorder
                imageMiddle
                bottomBorder
            }
        }
        .ignoresSafeArea()
    }
    
    var topBorder: some View {
        return Group {
            ZStack {
                Rectangle()
                    .fill(.green)
                    .frame(minHeight: borderHeight, maxHeight: borderHeight)
                Button {
                    print("tap")
                } label: {
                    Image(systemName: "hand.tap.fill")
                        .foregroundColor(.black)
                }
            }
        }
    }
    
    var bottomBorder: some View {
        return Group {
            Rectangle()
                .fill(.green)
                .frame(minHeight: borderHeight, maxHeight: borderHeight)
        }
    }
    
    var imageMiddle: some View {
        return Group {
            Color.black.overlay(
                Image("cat")
                    .scaledToFill()
            )
            .clipped()
        }
    }

How can I expose that button to a user's tap?

1

1 Answer 1

1

Adding .allowsHitTesting(false) to your image view will fix it. However, it seems like the wrong approach.

VStack {
    topBorder
    imageMiddle
        .allowsHitTesting(false) // <- This will fix your problem.
    bottomBorder
}

I would recommend using another approach to add your borders on top of the image instead. Something like this:

ZStack {
    imageMiddle
    VStack {
        topBorder
            .overlay(alignment: .bottom) {
                Rectangle().frame(minHeight: 0, maxHeight: 10)
            }
        Spacer()
        bottomBorder
            .overlay(alignment: .top) {
                Rectangle().frame(minHeight: 0, maxHeight: 10)
            }
    }
}
.ignoresSafeArea()
Sign up to request clarification or add additional context in comments.

1 Comment

Much more elegant a solution! Thank you.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.