【问题标题】:How to Pass More than Just a String in NSItemProvider in SwiftUI Drag and Drop如何在 SwiftUI 拖放中在 NSItemProvider 中传递不仅仅是一个字符串
【发布时间】:2021-06-09 20:29:48
【问题描述】:

我在 Stack Overflow 上查看了一些关于使用 SwiftUI 进行拖放重新排序的问题,这个问题特别有用:SwiftUI | Using onDrag and onDrop to reorder Items within one single LazyGrid?

我希望扩展此功能,在我的 SWifUI 应用程序中,我将某些项目从一个项目列表拖到另一个项目列表。假设我有一个Task 列表:

//TaskView.swift

ScrollView{
  VStack{
    ForEach(model.tasks, id: \.self){ task in
      Text(task.name)
        .onDrag{
          NSItemProvider(object: String(task.id) as NSString)
        }
    }
  }
}

...我还有一个 Project 列表,我可以将 Task 拖到该列表上以将其移动到该项目:

//ProjectView.swift

ScrollView{
  VStack{
    ForEach(model.projects, id: \.self){ project in
      Text(project.name)
        .onDrop(of: [UTType.text], delegate: ProjectDropDelegate(project: project))
    }
  }
}

我正在努力解决的部分是在我的ProjectDropDelegate 中,我试图确定几件事:

  1. 什么样的物体落在我身上? (必须是一项任务)
  2. 如果是任务,它的id 是什么,以便我可以对其采取行动? (或者,理想情况下,我会使用整个 Task 对象)

我不知道如何让.onDrag 中的NSItemProvider 使用字符串以外的任何内容,并且仍然可以使用我的SwiftUI 拖放功能。值得一提的是,我的 TaskProject 对象是 Core Data 类。

如何使NSItemProvider 包含键值对,以便我可以传递类型标识符字符串,如myapp.task(用于上述#1)和id(用于#2)?

【问题讨论】:

  • 好资源:exploringswift.com/blog/…(解释使用NSItemProviderReadingNSItemProviderWriting),swiftui-lab.com/drag-drop-with-swiftui(显示使用itemProviders(for:) 在放置委托中,您需要检查您的自定义使用第一个链接中说明的方法注册的类型。
  • 这是否回答了您的问题stackoverflow.com/a/60832686/12299030
  • 感谢您的快速回复。我之前查看了所有这些链接,但仍然对我的Task 对象如何表现得像一个似乎自动与UTType 兼容的图像(TIFF 或UIImage)感到困惑。 Exploring Swift 这篇文章可能是我需要的,但它有点复杂,所以我需要一些时间来消化它。

标签: swift swiftui nsitemprovider


【解决方案1】:

经过进一步调查,我找到了一种更简单的方法来处理这一切。如果您需要做的只是将数据从应用程序的一个部分移动到另一个部分,我认为NSItemProvider 有点牵强附会。这就是我的做法,它似乎工作得很好。

我在生成任务列表时提到了model.tasks。以下是关于它的更多信息:

class TaskModel: ObservableObject {
  static let shared = TaskModel()
  
  @Published var tasks = [Task]()
  var draggedTask: Task? //<-- I added this
  //...
}

我为我的模型添加了一个draggedTask 可选,然后我将它设置在我的onDrag 修饰符中,如下所示:

Text(task.name)
  .onDrag{
    model.draggedTask = task
    NSItemProvider(object: NSString())
  }

我只是将一个空的String 对象传递给NSItemProvider 以满足其拖动某些东西的要求。然后在我的ProjectDropDelegate 中,我可以拥有我需要的所有东西,包括设置悬停的 UI 状态:

import SwiftUI
import UniformTypeIdentifiers

struct ProjectDropDelegate: DropDelegate {
  @Binding var hovered: Bool
  var project: Project?
  var modelTask = TaskModel.shared
  
  //MARK: Check before we start
  func validateDrop(info: DropInfo) -> Bool {
    //Allow the drop to begin with any String set as the NSItemProvider
    return info.hasItemsConforming(to: [UTType.text])
  }
  
  //MARK: Drop UI State
  func dropEntered(info: DropInfo) {
    //Show the hovered state if we have a draggedTask
    hovered = modelTask.draggedTask != nil
  }
  func dropExited(info: DropInfo) {
    hovered = false
  }
  
  //MARK: Drop and Save
  func performDrop(info: DropInfo) -> Bool {
    if let task = modelTask.draggedTask{
      //Save my task using modelTask...
      return true
    }else{
      return false
    }
  }
}

这比我最初做的要简单得多。

【讨论】:

  • 为什么会有“var project: Project?”在那个 DropDelegate 中?它看起来不像在做任何事情。
  • 我删除了使用它的代码,但它可以在performDrop 函数中保存对task 的更改(我更改了project 对象上的project 属性)。 ?
  • 这是一个很好的解决方法,但仅适用于您自己的应用程序。
猜你喜欢
  • 2015-11-29
  • 2023-03-21
  • 2018-02-08
  • 1970-01-01
  • 2016-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-29
相关资源
最近更新 更多