如何在 SwiftUI 拖放中传递 NSItemProvider 中的不仅仅是字符串

问题描述

我已经查看了 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 对象)

我不知道如何让 NSItemProvider 中的 .onDrag 使用字符串以外的任何内容,并且仍然使用我的 SwiftUI 拖/放功能。就其价值而言,我的 TaskProject 对象是核心数据类。

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

解决方法

经过进一步调查,我找到了一种更简单的方法来处理这一切。如果您需要做的只是将数据从应用程序的一个部分移动到另一个部分,我认为 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
    }
  }
}

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...