首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在NSItemProvider中的SwiftUI拖放中传递多个字符串

如何在NSItemProvider中的SwiftUI拖放中传递多个字符串
EN

Stack Overflow用户
提问于 2021-03-11 19:42:35
回答 2查看 2.7K关注 0票数 5

我回顾了关于SwiftUI拖放重新排序的堆栈溢出的一些问题,这个问题特别有用:SwiftUI | Using onDrag and onDrop to reorder Items within one single LazyGrid?

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

代码语言:javascript
复制
//TaskView.swift

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

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

代码语言:javascript
复制
//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)?

EN

回答 2

Stack Overflow用户

发布于 2021-03-11 21:56:55

经过进一步的调查,我找到了一个更简单的方法来处理这一切。我认为NSItemProvider有点像鲱鱼,如果你只需要将数据从应用程序的一个部分移到另一个部分就行了。我是这样做的,看起来效果很好。

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

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

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

代码语言:javascript
复制
Text(task.name)
  .onDrag{
    model.draggedTask = task
    NSItemProvider(object: NSString())
  }

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

代码语言:javascript
复制
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
    }
  }
}

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

票数 5
EN

Stack Overflow用户

发布于 2022-01-14 13:24:05

遇到了同样的问题。像这样的东西会有用的:

代码语言:javascript
复制
NSItemProvider(item: letter as NSString, typeIdentifier: "public.plain-text")

这样做是行不通的:

代码语言:javascript
复制
NSItemProvider(item: letter as NSString, typeIdentifier: "com.myapp.mytype")

Bug还是特性?特性!

第二个自定义类型标识符不能工作的原因是该UTI尚未在任何地方声明(尚未)。

解决方案是将您的自定义类型声明为UTI:

打开项目>目标>信息>导出类型Identifiers

  • Add类型
  1. 类型:
    • 标识符:com.myapp.mytype
    • 符合:public.data

现在,这将起作用(您可以提交任何支持NSSecureCoding的对象):

代码语言:javascript
复制
NSItemProvider(item: letter as NSString, typeIdentifier: "com.myapp.mytype")

构建并运行您的应用程序,重新排序您的列表现在将工作!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66589447

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档