I have 4 Views: A, B, C and D
A and B are inside the VStack C.
C and D both are in a ZStack.
I want A to be beneath B, therefore both are in a VStack.
The problem is, that I want to set the zIndex of A to 1, B to 3 and D to 2. The zIndex only applies to Views inside the same View-Hierarchy. But if I put A, B and D into the same ZStack, then A and B are no longer below each other. If I put D inside the VStack C, then it is not on top of A and B any more...
How can I solve this puzzle?
I want to achieve this, because in my case, D is an overlay that should detect click events on everything but on B (which is a pop-up-menu). A is a button to show the menu B. Clicks on D are supposed to close the menu B. But the items in B should still be clickable.
Here is an example:
struct Test: View {
@State private var isMenuVisible = false
var body: some View {
ZStack {
VStack { //C
Button(action: { //A
isMenuVisible.toggle()
}, label: {
Text("Open Menu")
})
if (isMenuVisible) {
Rectangle() //B
.fill(Color.blue)
.overlay {
Button(action: {
print("is clickable!")
}, label: {
Text("Menu-Button")
})
}
}
Spacer()
}
if (isMenuVisible) {
Color.red // D
.opacity(0.6)
.onTapGesture {
isMenuVisible.toggle()
}
}
}
}
}
If I put the if-Statement inside the ZStack, then it works, but then not the entire screen is covered.
VStack
|---OptionButton
|---ZStack
|---Dismisser
|---Menu
fix/known sized button
or dynamic size observer
struct Test: View {
@State private var isMenuVisible = false
//@State private var dynamicHeight = 50.0
var body: some View {
ZStack(alignment: .top) {
Color.clear // make ZStack wider
Button {
isMenuVisible.toggle()
} label: {
Text("Open Menu")
}
.frame(height: 50)//dynamicHeight = observeHeight
.border(.green, width: 1)
if isMenuVisible {
Color.red //Dismisser
.opacity(0.5)
.onTapGesture {
isMenuVisible.toggle()
}
VStack {
Button(action: {
print("is clickable 1!")
}, label: {
Text("Menu-Button-1")
})
Button(action: {
print("is clickable 2!")
}, label: {
Text("Menu-Button-2")
})
}
.border(.green, width: 1)
.padding(.top, 50)//.padding(.top, dynamicHeight)
}
}
}
}
for observing live high of any view
.overlay(
GeometryReader { geo in
Color.clear.onAppear {
dynamicHeight = geo.size.height
}
.onChange(of: geo.frame(in: .global)) { _ in
dynamicHeight = geo.size.height
}
}
)