iosswiftswiftuiz-index

zIndex in LazyVGrid is not updated on redraw


I want to change items in LazyVGrid on tap. I've implemented color and zIndex to be depended on selectedItemIndex, which is changed when item is tapped.

import SwiftUI

struct FilmRoll: View {
    @State private var selectedItemIndex: Double = 5
    
    var body: some View {
        
        ZStack {
            Color.black.ignoresSafeArea()
            ScrollView {
                LazyVGrid(columns: [GridItem(), GridItem(), GridItem()]) {
                    ForEach(1..<13) { index in
                        Rectangle()
                            .fill(Color(
                                red: (selectedItemIndex == Double(index)) ? 1 : Double(index)/24.0 + 0.5,
                                green: 0,
                                blue: 0))
                            .zIndex((selectedItemIndex == Double(index)) ? 1 : 0)
                            .frame(width: 180, height: 180)
                            .border(Color.black)
                            .rotationEffect(.degrees(45))
                            .onTapGesture {
                                selectedItemIndex = Double(index)
                                print("selected item \(selectedItemIndex)")
                            }
                    }
                }
            }
        }
    }
}

Result is that color is updated when @State selectedItemIndex changes, but zIndex stays the same as it was on start. What am I missing?

https://imgur.com/a/ybFeY0N

enter image description here


Solution

  • To achieve what you want, you could try this approach adding an id to the ForEach to force it to refresh. Note, it is better to have Int types for comparisons, as shown in the code:

    struct ContentView: View {
        var body: some View {
            FilmRoll()
        }
    }
    
    struct FilmRoll: View {
        @State private var selectedItemIndex: Int = 5 // <-- here
        
        var body: some View {
            ZStack {
                Color.black.ignoresSafeArea()
                ScrollView {
                    LazyVGrid(columns: [GridItem(), GridItem(), GridItem()]) {
                        ForEach(1..<13) { index in
                            Rectangle()
                                .fill(Color(
                                    red: (selectedItemIndex == index) ? 1 : Double(index)/24.0 + 0.5,
                                    green: 0,
                                    blue: 0))
                                .zIndex(selectedItemIndex == index ? 1 : 0)
                                .frame(width: 180, height: 180)
                                .border(.black)
                                .rotationEffect(.degrees(45))
                                .onTapGesture {
                                    selectedItemIndex = index
                                    print("----> selected item \(selectedItemIndex)")
                                }
                        }
                        .id(selectedItemIndex) // <-- here
                    }
                }
            }
        }
    }