Overlaid items hide behind neighbouring views

Hello, I'm very much new to SwiftUI, I am trying do develop something small, a chess app as a introduction, and I've come to an problem shown here:

If I offset an overlay by an positive number (hardcoded in this example but the problem occurred to me when I started to try moving pieces around) pieces hide behind tiles below it (the problem doesn't occur when moving up). I have tried to glue zIndex(0) to everything there is, and both overlaying the Piece over the Tile and using ZStack gave me the same results.

When I use positive y offsets it seems to be working fine:

Here is my relevant code, sorry for these .zindexes :

private func pieceView(for coords: Coords) -> some View {
        if let piece: Piece = model.initialState[coords] {
            return AnyView(PieceView(type: piece.figure, side: piece.side)
                .zIndex(1)
            )
            
        } else {
            return AnyView(EmptyView().zIndex(0))
        }
    }
    
    var body: some View {
        GeometryReader {geometry in
            let size = min(geometry.size.width, geometry.size.height)

                VStack( spacing: 0.0) {
                    ForEach((0..<8).reversed(), id: \.self) {
                        rowIndex in
                        HStack(spacing: 0) {
                            ForEach((0..<8), id: \.self) { columnIndex in
                                TileView(x: rowIndex, y: columnIndex)
                                    .frame(width: size / 8, height: size / 8)
                                    .overlay{
                                        pieceView(for: Coords(x: columnIndex, y: rowIndex))
                                            .offset(y: -20)
                                            .zIndex(10)
                                    }
                            }
                        }.zIndex(0)
                    }.zIndex(0)
                }.zIndex(0)
            }
        }

Thanks for help!

Why don't you set zIndex to 10 directly in pieceView instead of 1 ?

the code in your body is executed in the order you write it. Your first ForEach draws each row from the top downwards. Each row contains a TileView (a brown or yellow square) and a pieceView, which may draw nothing at all, but if it draws something, it is an overlay drawn below the tile (if the offset is negative). The next row you draw will draw over that overlay.

To fix this, make the content something like this

ZStack {
BoardView()
PiecesView()
}

The BoardView doesn't change as your chess game changes. The PiecesView would be dependent on the model of the chess game as it progresses. If it were me, I'd iterate through all the pieces in the game, and draw them at their respective x,y offsets.

Your pieceView function looks up a pieceView based on the current co-ordinate on the board, but it does so at a different co-ordinate for each square, then applies an offset from that square when drawing the overlay. I think I'd prefer to be drawing at an offset from a fixed location, like the bottom left of the board.

Finally I went with something similar to what you suggested :

    var body: some View {
        GeometryReader {geometry in
            let size = min(geometry.size.width, geometry.size.height)
            let tileSize = size / 8
            VStack( spacing: 0.0) {
                ForEach((0..<8).reversed(), id: \.self) {
                    rowIndex in
                    HStack(spacing: 0) {
                        ForEach((0..<8), id: \.self) { columnIndex in
                            TileView(x: rowIndex, y: columnIndex)
                        }
                    }
                }
            }.overlay(alignment: .bottomLeading){
                ForEach(Array(model.initialState.keys), id:\.self) {
                    let (row, column) = $0.tuple()
                    let piece = model.initialState[$0]!
                    let offset = model.offset(piece: piece, val: tileSize)
                    PieceView(type: piece.figure, side: piece.side)
                        .frame(width: tileSize, height: tileSize)
                        .offset(x: CGFloat(row) * tileSize, y: -CGFloat(column) * tileSize)
                        .offset(offset)
                }
            }
        }
    }

I thought Z Indexes are global ... then what they refer to ?

I played around a bit with zIndex. It applies to the rendering order within one View, it isn't global. It would be Really Hard to make a system where it is global - you can't predict what other Views are using for their zIndex values. Normally the rendering order is dictated by the order of appearance in the View's description. I can only see an application for zIndex if you are parameterizing the rendering order. If the zIndex is a constant you may as well just write the View's description in a different order.

Overlaid items hide behind neighbouring views
 
 
Q