【问题标题】:SwiftUI: Adding .onDrag blocks clicking/selecting an item in the macOS sidebarSwiftUI:添加 .onDrag 阻止单击/选择 macOS 侧边栏中的项目
【发布时间】:2021-01-31 14:25:07
【问题描述】:

我的 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()
    ]
}

【问题讨论】:

  • 没有Minimal Reproducible Example 无法帮助您解决问题。
  • 谢谢@loremipsum!我添加了一个最小可重现示例。
  • 我遇到了同样的行为,NavigationLink 中的 Dragable View 会破坏正常的 NavigationLink 行为。有时可以点击链接,有时不能。也在寻找解决方案。箭头键工作正常,您可以在列表中上下移动,但使用鼠标似乎有问题。
  • 发生的情况是,当您单击文本时,单元格没有被选中。当您在文本外部单击时,单元格将被选中。解决方法是使用通过 State var 控制选择的列表,并将 TapGesture 添加到您的 Text 并更新 State var。挑战在于区分命令点击和普通点击,因为选择行为应该表现不同

标签: swiftui swiftui-list swiftui-navigationlink


【解决方案1】:

我遇到了同样的问题,据我所知,它实际上是bug in SwiftUI。我也许可以为讨论提供更多细节:

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

Since I don't have enough reputation yet, please click this link to see the image.

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

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

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) }
    }
  }
}

希望这会有所帮助。来自巴西的欢呼!

【讨论】:

  • 您的观察是正确的,点击文本不会选择单元格,点击背景会选择单元格。解决方法是在文本上添加点击手势并在点击手势中更新您的@State private var selected。挑战在于区分命令点击和普通点击,因为选择行为应该不同
猜你喜欢
  • 1970-01-01
  • 2020-08-29
  • 1970-01-01
  • 2011-06-18
  • 1970-01-01
  • 1970-01-01
  • 2022-12-22
  • 1970-01-01
相关资源
最近更新 更多