iOS 11拖放drop:在标准日历应用

时间:2017-08-02 10:06:32

标签: calendar drag-and-drop ios11

我正在尝试在Xcode 9测试版的应用中集成iOS 11拖放功能。 我很有兴趣创建一个可以被标准日历应用程序理解的NSItemProvider。我的拖动从UITableView开始,因此只实现了一个dragDelegate方法。

到目前为止,我尝试了以下内容:

    let text = "Rendez-vous at \(clientName)"
    let data = text.data(using: .utf8)

    let itemProvider = NSItemProvider()
    itemProvider.registerDataRepresentation(forTypeIdentifier: kUTTypeCalendarEvent as String, visibility: .all) { completion in
        completion(data, nil)
        return nil
    }

    let dragItem = UIDragItem(itemProvider: itemProvider)

并且还尝试使用类型标识符kUTTypePlainText。没有运气,日历应用程序没有注册掉落。

我找不到任何关于此的官方文档。我希望日历应用程序正在寻找一些标准的日历数据,这不仅限于相互通信的标准应用程序。例如,您可以从notes应用程序拖动文本并将其放入日历中以创建活动。

任何人都知道我可以尝试什么?

提前致谢。

1 个答案:

答案 0 :(得分:3)

TL; DR :让默认iOS日历应用识别符合NSItemProviderWriting协议的自定义对象的秘密因素是"com.apple.ical.ics"类型标识符并导出您的自定义对象作为iCalendar字符串(vEvent)。

我已经玩了好几天了,我终于成功了!我会尝试尽可能地分解我的步骤。

  1. 创建符合NSItemProviderWriting的自定义对象:
    • 要符合协议,您需要实施 writableTypeIdentifiersForItemProviderloadData(withTypeIdentifier:, forItemProviderCompletionHandler:)
    • 标识符数组是您可以以保真度顺序首先以最高保真度导出的类型标识符列表。因此,请先放置自定义类型标识符,然后再包含"com.apple.ical.ics"
    • 上面提到的loadData函数将尝试查找拖动目标(此方案中的日历应用程序)支持的标识符,以及您的应用程序也支持的标识符,尝试首先获得最高保真度。
  2. 例如:

    public static var writableTypeIdentifiersForItemProvider: [String] {
        return ["com.yourcompany.myEvent", "com.apple.ical.ics"]
    }
    
    public func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Void) -> Progress? {
        switch typeIdentifier {
        case "com.yourcompany.myEvent": // Your custom handling goes here
        case "com.apple.ical.ics": completionHandler(createVEvent(), nil)
        default: completionHandler(nil, YourAppError.someCustomError)
        }
    
        return nil
    }
    
    1. 使用您的自定义事件信息创建iCalendar vEvent字符串:
      • 此步骤与来自WWDC 2017的Session 227中的演示非常相似,他们为自定义联系人创建vCard字符串。从该会话中签出演示项目。
      • 基本上,日历应用程序支持一些特定类型的类型标识符,而iCal格式就是其中之一。因此,您只需要创建一个帮助方法,将自定义事件类型转换为iCalendar字符串。
      • 我不会详细了解vEvent s,但有很多好消息herehere
    2. 这是一个建议:

      private func createVEvent() -> Data? {
          let today = Date()
      
          let dateFormatter = DateFormatter()
          dateFormatter.dateFormat = "yyyyMMdd'T'HHmmss'Z'"
          dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
      
          let startDateString = dateFormatter.string(from: startDate)
          let endDateString = dateFormatter.string(from: endDate)
          let todayString = dateFormatter.string(from: today)
      
          var vCalendarText = "BEGIN:VCALENDAR\n"
          vCalendarText +=    "VERSION:2.0\n"
          vCalendarText +=    "PRODID:-//Your Company//App Name//EN\n"
          vCalendarText +=    "BEGIN:VEVENT\n"
      
          vCalendarText +=    "UID:\(identifier.uuidString)\n"
          vCalendarText +=    "SUMMARY:\(name)\n"
          vCalendarText +=    "DTSTAMP:\(todayString)\n"
          vCalendarText +=    "DTSTART:\(startDateString)\n"
          vCalendarText +=    "DTEND:\(endDateString)\n"
      
          vCalendarText +=    "END:VEVENT\n"
          vCalendarText +=    "END:VCALENDAR"
      
          return vCalendarText.data(using: .utf8)
      }
      

      ↑类似于我之前提到过的那个会话演示中的createVCard()函数......

      那就是它!这几乎就是你所需要的。困难的部分是知道日历应用程序支持的标识符以及如何创建vEvent。感谢quiker找到支持的标识符。

      最后一个提示:您可以使用this nifty tool here验证您的iCalendar字符串。

      请注意,这只允许删除您的自定义对象。 将一个事件从日历拖动到您的应用程序是一个不同的故事,但您可以从我的提示中找到它。 :)

      快乐的编码!