I have some views that should be brought to the top when dragged.
However, while I can confirm via debugger and logging that the zIndex is being updated, the views are never actually reordered.
Here is an example project that shows the issue. The rectangle being dragged should float to the top.
However, while I can confirm via debugger and logging that the zIndex is being updated, the views are never actually reordered.
Here is an example project that shows the issue. The rectangle being dragged should float to the top.
Code Block swift import SwiftUI class XRectModel: ObservableObject, Identifiable, Hashable, Equatable { var id = UUID() static func == (lhs: XRectModel, rhs: XRectModel) -> Bool { lhs.id == rhs.id } func hash(into hasher: inout Hasher) { hasher.combine(id) } init(color: Color, order: Double) { self.color = color self.order = order } @Published var color: Color @Published var order: Double } struct XRect: View { static var maxorder: Double = 0 @State var rect: XRectModel @State var pos: CGSize = CGSize() var drag: some Gesture { DragGesture() .onChanged { pos in self.pos = pos.translation XRect.maxorder += 1 rect.order = XRect.maxorder print("Rect: \(rect.color.description), Order: \(rect.order)") } } var body: some View { Rectangle() .foregroundColor(rect.color) .frame(width: 200, height: 200, alignment: .center) .offset(pos) .gesture(drag) } } struct ContentViews: View { var rects = [XRectModel(color: Color.green, order: 0), XRectModel(color: Color.yellow, order: 0), XRectModel(color: Color.red, order: 0)] var body: some View { ZStack { Color.blue ForEach(rects, id: \.self) { rect in XRect(rect: rect) .zIndex(rect.order) } } } } @main struct XRectApp: App { var body: some Scene { WindowGroup { ContentViews() } } }
Unfortunately, SwiftUI cannot detect changes of properties in an Array, when the Element is a reference type.
(Even when you add @State on the Array declaration or you add @Published to the properties.)
So, changes to color or order do not trigger UI updates in ContentViews.
If you make XRectModel struct, and add @State to rects, you will find zIndex works correctly:
(Even when you add @State on the Array declaration or you add @Published to the properties.)
So, changes to color or order do not trigger UI updates in ContentViews.
If you make XRectModel struct, and add @State to rects, you will find zIndex works correctly:
Code Block struct XRectModel: Hashable { var id = UUID() var color: Color var order: Double } struct XRect: View { static var maxorder: Double = 0 @Binding var rect: XRectModel @State var pos: CGSize = CGSize() var drag: some Gesture { DragGesture() .onChanged { pos in self.pos = pos.translation XRect.maxorder += 1 rect.order = XRect.maxorder print("Rect: \(rect.color.description), Order: \(rect.order)") } } var body: some View { Rectangle() .foregroundColor(rect.color) .frame(width: 200, height: 200, alignment: .center) .offset(pos) .gesture(drag) } } struct ContentViews: View { @State var rects = [XRectModel(color: Color.green, order: 0), XRectModel(color: Color.yellow, order: 0), XRectModel(color: Color.red, order: 0)] var body: some View { ZStack { Color.blue ForEach(rects.indices, id: \.self) { index in XRect(rect: $rects[index]) .zIndex(rects[index].order) } } } }