2017-08-02 55 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值,則放置成功,但放棄項目時會忽略日曆中的位置。這種類型打破了我想要創建事件的日期和時間在視覺上丟棄元素的目的。任何想法 ? –