I'm trying to display overlapping images and when one image is selected and moved it is brought to the front by setting .zIndex. The code works fine when the images are just in one ZStack or just in one HStack but when the two are nested it doesn't work. Does anyone know what code changes are required to make this function the way I want it to?
enum DragState {
case good
case bad
}
struct MyObject: View {
@State var dragAmount = CGSize.zero
@State var dragState = DragState.bad
var myImage: Image = Image("myImage")
var onChanged: ((CGPoint, MyObject) -> DragState)?
var body: some View {
myImage
.resizable()
.frame(width: 100, height: 150)
.offset(dragAmount)
.zIndex(dragAmount == .zero ? 0 : 1)
.gesture(
DragGesture(coordinateSpace: .global)
.onChanged {
self.dragAmount = CGSize(width: $0.translation.width, height: $0.translation.height)
self.dragState = self.onChanged?($0.location, self) ?? .bad
}
.onEnded {
_ in
self.dragAmount = .zero
})
}
}
struct ContentView: View {
@State private var cardFrames = [CGRect](repeating: .zero, count: 7)
var body: some View {
var i = 0
VStack (alignment: .trailing, spacing: -85) {
ForEach(0..<3) { row in
HStack {
ForEach(row..<3) { col in
MyObject()
.allowsHitTesting(true)
.overlay(
GeometryReader { geo in
Color.clear
.onAppear {
self.cardFrames[i] = geo.frame(in: .global)
i = i + 1
}
}
)
}
}
}
}
}
func moved(p1:CGPoint, object: MyObject) -> DragState {
return .good
}
}
Using a ZStack and positioning MyObject directly seems to achieve pretty well what you expect.
struct ContentView: View {
var body: some View {
ZStack() {
ForEach(0..<3) { row in
ForEach(0..<3) { col in
MyObject()
.offset(x: 120 * CGFloat(col-1), y: 160 * CGFloat(row))
}
}
}
}
}