0

I have a main view consisting of a zStack with a background image at the bottom, a user-loaded image above that, and two toolbars at the top. The toolbars are at the vertical top and bottom of the view. I want those toolbars to appear semi-transparent with background images matching the main view's background image in size and position. If the user drags or scales their image to overlap with the toolbars, it should be obscured by them. To accomplish that, I've built those toolbar views as zStacks with the same background image aligned to the top or bottom, respectively, and clipped the content to match the height of the toolbars.

My problem is that the clipped content of those toolbar views blocks gestures on the underlying, user-loaded image. To help visualize the problem, I've linked a screenshot of the debug view hierarchy for the main view (MockScoringView).

Here's the code for the main view:

GeometryReader { geometry in
            ZStack {

                Rectangle()
                    .foregroundColor(.blue)
                    .frame(width: geometry.size.width, height: geometry.size.height)
                    .offset(x: self.baseOffset.width + self.newOffset.width, y: self.baseOffset.height + self.newOffset.height)
                    .scaleEffect(self.scale)
                    .gesture(DragGesture()
                        .onChanged { value in
                                self.newOffset.width = value.translation.width / self.scale
                                self.newOffset.height = value.translation.height / self.scale
                        }
                        .onEnded { value in
                                self.baseOffset.width += self.newOffset.width
                                self.baseOffset.height += self.newOffset.height
                                self.newOffset = CGSize.zero
                        }
                    )

                VStack(spacing: 0) {
                    MockTopToolbarView()

                    Spacer()

                    MockBottomToolbarView()
                }
            }
        }

And the code for the top toolbar view, which is very similar to the one on bottom:

ZStack {
            Image("Background")
                .resizable()
                .scaledToFill()
                .frame(height: 56, alignment: .top)
                .clipped()

            Rectangle()
                .foregroundColor(.toolbarGray)
                .frame(height: 56)
        }

I'd like to modify the content of the toolbar views' backgrounds so they do not block gestures from reaching the user-loaded image.

Debug View Hierarchy

Jesse
  • 25
  • 7
  • [How to create a Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) – Asperi Jun 09 '20 at 04:05

1 Answers1

1

You could set allowsHitTesting(false) on the background images.

Alternatively, since you do not want the user image to be visible behind the toolbars you could also just add the Rectangle and toolbars to a single VStack.

ZStack {
    Image("Background")
            .resizable()
            .scaledToFill()
    VStack {
        TopToolBar()
        Rectangle()
            .foregroundColor(.blue)
            ...
        BottomToolBar()
    }
}
Jack Goossen
  • 799
  • 4
  • 14
  • Setting `allowsHitTesting(false)` works! If I put them all in the same vStack, when the image is moved or resized it stays under the bottom toolbar (desired) but goes over the top toolbar (undesired). – Jesse Jun 10 '20 at 22:12
  • @Jesse You can add .clipped() to the Rectangle. This will prevent child views from being drawn outside of its bounds. – Jack Goossen Jun 11 '20 at 04:06
  • @Jesse ...or use ‘.zIndex(1)’ on the top toolbar. This way the toolbar will be drawn on top. – Jack Goossen Jun 11 '20 at 04:26