如果内容视图具有点击手势操作,SwiftUI ForEach 的 onMove() 修饰符将停止工作

SwiftUI ForEach's onMove() modifier stop working if the content view has tap gesture action

我想制作一个列表视图,可以拖动其中的内容进行重新排序并点击查看详细信息。 但是当我在内容视图中添加 onTapGesture() 操作时,onMove() 操作停止工作。

示例代码:

import SwiftUI

struct TestTapAndMove: View {
    @State private var users = ["Paul", "Taylor", "Adele"]

    var body: some View {
            List {
                ForEach(users, id: \.self) { user in
                    VStack {
                        Text("user: \(user)").font(.headline)
                        
                        Divider()
                    }.background(Color.gray)

                    // The TapGesture will result in onMove action not working.
                    .onTapGesture(perform: {
                        print("tap!")
                    })
                }
                .onMove(perform: move)
            }
    }

    func move(from source: IndexSet, to destination: Int) {
        print("onMove!")
        users.move(fromOffsets: source, toOffset: destination)
    }
}

是否有任何解决方案可以使点击和移动动作协同工作?

作为解决方法,您可以使行的某些特定部分可点击,例如下面示例中的文本(或一些添加的自定义形状或普通按钮)

VStack {
    Text("user: \(user)").font(.headline)
      .onTapGesture(perform: {
            print("tap!")
      })
    Divider()
}.background(Color.gray)

备选方案: 您可以将辅助自定义视图添加为行覆盖,这将处理 tap/mouseDown 视图操作(并且不会破坏药物)

class TapHandlerView: NSView {
    override func mouseDown(with event: NSEvent) {
        super.mouseDown(with: event)   // keep this to allow drug !!
        print("tap")
    }
}

struct TapHandler: NSViewRepresentable {
    func makeNSView(context: Context) -> TapHandlerView {
        TapHandlerView()
    }

    func updateNSView(_ nsView: TapHandlerView, context: Context) {
    }
}

并使用它

VStack {
    Text("user: \(user)").font(.headline)
    Divider()
}.background(Color.gray)
.overlay(TapHandler())         // << here !!

测试 Xcode 12.0 / macOS 10.15.6