首页 > 解决方案 > SwiftUI:添加 .onDrag 块单击/选择 macOS 侧边栏中的项目

问题描述

我的 macOS 应用程序的侧边栏中有一个列表。当我添加.onDrag修饰符时,拖动NSItemProvider可以正常工作,但是单击/选择要触发的项目NavigationLink会被阻止。

struct ContentView: View {
    var body: some View {
        NavigationView {
            List(Data.items) { item in
                NavigationLink(
                    destination: Text(item.text),
                    label: {
                        Text(item.text)
                          .lineLimit(5)
                           // Enabling dragging with .onDrag {} disables click and selection:
                          .onDrag { return NSItemProvider(object: item.url as NSURL) }
                    })
            }
            Text("Placeholder")
        }
    }
}

如何在保持正常列表选择行为不变的同时添加拖动行为?

这是最小可重现示例的其余部分:

import SwiftUI

@main
struct ListDragExampleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

struct Data {
    struct Item: Identifiable {
        let id = UUID()
        let text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
        let url = URL(string: "http://example.com")!
    }
    static let items = [
        Item(),
        Item(),
        Item()
    ]
}

标签: swiftuiswiftui-listswiftui-navigationlink

解决方案


我遇到了同样的问题,据我所知,这实际上是SwiftUI 中的一个错误。我也许可以为讨论提供更多细节:

  • 它与 a 没有直接关系NavigationLink。我有一个List带有自定义项目视图的普通视图,它呈现出相同的不稳定行为;
  • 在我的自定义项目视图中,有些区域没有实际内容View,例如视图旁边的空白区域Text。当我点击这些区域(“背景”,见下图)时,我仍然可以选择项目,但拖动机制不起作用;
  • 当将拖动的项目拖放到另一个项目上时,接受拖放的区域仅由目标项目的子视图的框架组成。如果我尝试放在List项目的“背景”区域,它不会接受它。

由于我还没有足够的声誉,请单击此链接查看图像。

总的来说,在我看来,只要接受拖放的项目具有子视图(简单Text或更复杂的布局,例如我在图片中显示的布局),只要鼠标光标在其中一个,拖动机制就会禁用选择这些子视图,同时只允许通过在其框架内开始或结束来进行拖放。

Text在下面的代码中,选择机制将在单击“Short”项右侧的区域时起作用,但只有在视图框架内开始时才会触发拖动。

struct ExampleList: View {
  private let data = ["Short", "Average", "Loooooooooooong"]
  @State private var selected = Set<String>()

  var body: some View {
    List(data, id: \.self, selection: $selected) { text in
      Text(text) // Clicking outside the frame selects it...
                 // ...but clicking inside starts the drag mechanism.
        .onDrag { NSItemProvider(object: text as NSString) }
    }
  }
}

希望这可以帮助。来自巴西的欢呼!


推荐阅读