admin管理员组

文章数量:1405112

I'm trying to drag a group of elements and I want the element to be on top of all other elements in the group when I drag it. I'm trying to change the zIndex of the dragged element but for some reason it doesn't work... Maybe someone who knows this stuff can point out my mistake

struct DragShapesView: View {
    
    var body: some View {
        let layout = [GridItem(), GridItem()]
        
        LazyHGrid(rows: layout, spacing: 15) {
            ForEach(1..<5) { i in
                Circle()
                    .frame(width: 50, height: 50)
                    .overlay {
                        Text(String(i))
                            .font(.evolventaBold(25))
                            .foregroundColor(.white)
                    }
                    .draggable(
                        onChanged: { location in
                            
                        },
                        onEnded: {
                            
                        }
                    )
            }
        }
    }
}

modifier draggable is:

struct Draggable: ViewModifier {
    
    @State private var location: CGPoint = .zero
    @State private var offset: CGSize = .zero
    @State private var zIndex: Double = 0
    
    var onChanged: ((CGPoint) -> Void)?
    var onEnded: (() -> Void)?
    
    func body(content: Content) -> some View {
        content
            .zIndex(zIndex)
            .offset(offset)
            .gesture(
                DragGesture(coordinateSpace: .global)
                    .onChanged { value in
                        zIndex = Double.infinity
                        offset = value.translation
                        onChanged?(value.location)
                    }
                    .onEnded { _ in
                        zIndex = .zero
                        offset = .zero
                        onEnded?()
                    }
            )
    }
}

extension View {
    
    func draggable(onChanged: ((CGPoint) -> Void)?, onEnded: (() -> Void)?) -> some View {
        self.modifier(Draggable(onChanged: onChanged, onEnded: onEnded))
    }
}

I'm trying to drag a group of elements and I want the element to be on top of all other elements in the group when I drag it. I'm trying to change the zIndex of the dragged element but for some reason it doesn't work... Maybe someone who knows this stuff can point out my mistake

struct DragShapesView: View {
    
    var body: some View {
        let layout = [GridItem(), GridItem()]
        
        LazyHGrid(rows: layout, spacing: 15) {
            ForEach(1..<5) { i in
                Circle()
                    .frame(width: 50, height: 50)
                    .overlay {
                        Text(String(i))
                            .font(.evolventaBold(25))
                            .foregroundColor(.white)
                    }
                    .draggable(
                        onChanged: { location in
                            
                        },
                        onEnded: {
                            
                        }
                    )
            }
        }
    }
}

modifier draggable is:

struct Draggable: ViewModifier {
    
    @State private var location: CGPoint = .zero
    @State private var offset: CGSize = .zero
    @State private var zIndex: Double = 0
    
    var onChanged: ((CGPoint) -> Void)?
    var onEnded: (() -> Void)?
    
    func body(content: Content) -> some View {
        content
            .zIndex(zIndex)
            .offset(offset)
            .gesture(
                DragGesture(coordinateSpace: .global)
                    .onChanged { value in
                        zIndex = Double.infinity
                        offset = value.translation
                        onChanged?(value.location)
                    }
                    .onEnded { _ in
                        zIndex = .zero
                        offset = .zero
                        onEnded?()
                    }
            )
    }
}

extension View {
    
    func draggable(onChanged: ((CGPoint) -> Void)?, onEnded: (() -> Void)?) -> some View {
        self.modifier(Draggable(onChanged: onChanged, onEnded: onEnded))
    }
}
Share Improve this question edited Mar 23 at 9:58 Benzy Neez 23.5k3 gold badges15 silver badges44 bronze badges asked Mar 22 at 22:00 Alex BroAlex Bro 1117 bronze badges 0
Add a comment  | 

1 Answer 1

Reset to default 1

Unfortunately, changing the zIndex of items in a lazy grid does not work well.

  • One way to solve is to set an id on the LazyHGrid based on the item being dragged. This is demonstrated in the answers to LazyVGrid is not redrawn on .id(). This would probably mean, passing a binding to Draggable so that it can be updated with the id of the item being dragged.
  • Alternatively, .matchedGeometryEffect can be used. This is demonstrated in the answer to Cant change zIndex of LazyVGrid element to bring it to the front with animation (it was my answer).

To use .matchedGeometryEffect in your case, the following changes are needed:

  • Build the grid using hidden placeholders for the items.
  • The visible items are shown together in an overlay.
  • The visible items are matched to the placeholders using their indices as ids.

Here is an updated version of the example to show it working:

struct DragShapesView: View {
    private let colors: [Color] = [.red, .orange, .yellow, .green]
    private let layout = [GridItem(), GridItem()]
    @Namespace private var ns

    var body: some View {
        LazyHGrid(rows: layout, spacing: 15) {
            ForEach(Array(colors.enumerated()), id: \.offset) { i, _ in
                Color.clear
                    .frame(width: 100, height: 100)
                    .matchedGeometryEffect(id: i, in: ns)
            }
        }
        .overlay {
            ForEach(Array(colors.enumerated()), id: \.offset) { i, color in
                Circle()
                    .fill(color)
                    .overlay {
                        Text(String(i))
                            .font(.title) // .evolventaBold(25)
                            .foregroundStyle(.white)
                    }
                    .draggable(
                        onChanged: { location in },
                        onEnded: {}
                    )
                    .matchedGeometryEffect(id: i, in: ns, isSource: false)
            }
        }
    }
}

本文标签: iosIncorrect zindex calculation when draggingStack Overflow