2017-08-02 84 views
2

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

到目前为止,我已经试过如下:

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尝试。没有运气,日历应用不会注册掉落。

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

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

在此先感谢。

回答

2

TL; DR:秘密成分,以获取默认的iOS日历应用识别您的自定义对象符合NSItemProviderWriting协议是"com.apple.ical.ics"类型标识符和导出自定义对象的字符串的iCalendar(vEvent)。


我一直在玩这个几天,我终于设法得到它的工作!我会尝试尽可能地分解我的步骤。

  1. 创建符合NSItemProviderWriting自定义对象:
    • 要符合协议,你需要实现 writableTypeIdentifiersForItemProviderloadData(withTypeIdentifier:, forItemProviderCompletionHandler:)
    • 标识符数组是一个类型标识符列表,您可以按保真度顺序以最高保真度先输出。因此,请先将您的自定义类型标识符包含在内,然后包含"com.apple.ical.ics"
    • 上面提到的loadData函数将尝试查找拖动目标(本场景中的Calendar应用程序)支持并且您的应用程序也支持的标识符,尝试首先获得最高的保真度。

例如:

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 
} 
  • 创建的iCalendar vEvent串与自定义事件的信息:
    • 该步骤非常类似于来自WWDC 2017的Session 227演示文稿中,他们为自定义联系人创建了一个vCard字符串。从该会话中检出演示项目。
    • 本质上,日历应用程序支持几种特定类型的标识符,iCal格式就是其中之一。因此,您只需制作一个帮助器方法即可将您的自定义事件类型转换为iCalendar字符串。
    • 我不会详述vEvent s,但有很多好的信息herehere
  • 这里有一个建议:

    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字符串。

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

    快乐编码!

    +0

    哇,真棒的回应。今天我会测试一下,然后回过头来验证。非常感谢您提供所有这些细节的时间。 –

    +0

    嘿卢卡斯,我测试了你的例子,它效果很好。但有一件事情让我困扰。如果我没有放置DTSTART值,则失败。但是,如果我放置DTSTART值,则放置成功,但放弃项目时会忽略日历中的位置。这种类型打破了我想要创建事件的日期和时间在视觉上丢弃元素的目的。任何想法 ? –