粘贴格式化文本,而不是图像或HTML

我试图模拟iOS页面和Keynote应用程序的粘贴板行为。 简而言之,允许将基本NSAttributedString文本格式(即BIU)粘贴到UITextView中,而不是图像,HTML等等。

行为总结

  1. 如果您从Notes应用程序,Evernote或文本和图像中复制来自网站的格式化文本,Pages将只粘贴纯文本string
  2. 如果您从Pages或Keynote中复制格式化文本,则会将其格式化的文本粘贴到Pages,Keynote等其他位置。
  3. 一个不希望的后果,但也许很重要的是,Notes应用程序或Evernote都不会粘贴从Pages或Keynote复制的格式化文本。 我猜测应用程序之间的差异是使用NSAttributedStrings,而不是HTML?

这是如何完成的? 在Mac OS上,看起来您可以要求粘贴板返回不同types的自身,让它提供丰富的文本和string表示forms,并使用富文本作为首选。 不幸的是,iOS的readObjectsForClasses似乎不存在。 也就是说,我可以通过日志看到iOS有一个RTF相关types的粘贴板, 感谢这篇文章 。 我不能,但是,find一种方法来请求一个NSAttributedString版本的粘贴板内容,所以我可以优先考虑粘贴。

背景

我有一个应用程序,允许基本的NSAttributedString用户可编辑格式(即粗体,斜体,下划线)的文字在UITextViews。 用户想从其他应用程序(例如Safari中的网页,Notes应用程序中的文本)复制文本,以便粘贴到我的应用程序中的UITextView中。 允许粘贴板以默认方式运行意味着我可能最终得到我的应用程序无意处理的背景颜色,图像,字体等。 下面的例子显示了当粘贴到我的应用程序的UITextView中时,如何复制具有背景颜色的文本。

在这里输入图像说明

我可以通过inheritanceUITextView来克服1

- (void)paste:(id)sender { UIPasteboard *pasteBoard = [UIPasteboard generalPasteboard]; NSString *string = pasteBoard.string; NSLog(@"Pasteboard string: %@", string); [self insertText:string]; } 

意想不到的后果是,失去了保留从我的应用程序中复制的文本格式的能力。 用户可能想从我的应用程序中的一个UITextView复制文本,并粘贴到我的应用程序中的另一个UITextView。 他们会希望保留格式(即大胆,斜体,下划线)。

见解和build议表示赞赏。

一些复制/粘贴的好东西和想法,为你:)

 // Setup code in overridden UITextView.copy/paste let pb = UIPasteboard.generalPasteboard() let selectedRange = self.selectedRange let selectedText = self.attributedText.attributedSubstringFromRange(selectedRange) // UTI List let utf8StringType = "public.utf8-plain-text" let rtfdStringType = "com.apple.flat-rtfd" let myType = "com.my-domain.my-type" 
  • 覆盖UITextView副本:并使用您的自定义粘贴板typespb.setValue(selectedText.string, forPasteboardType: myType)
  • 允许富文本复制(复制:):

     // Try custom copy do { // Convert attributedString to rtfd data let fullRange = NSRange(location: 0, length: selectedText.string.characters.count) let data:NSData? = try selectedText.dataFromRange(fullRange, documentAttributes: [NSDocumentTypeDocumentAttribute: NSRTFDTextDocumentType]) if let data = data { // Set pasteboard values (rtfd and plain text fallback) pb.items = [[rtfdStringType: data], [utf8StringType: selectedText.string]] return } } catch { print("Couldn't copy") } // If custom copy not available; // Copy as usual super.copy(sender) 
  • 要允许富文本粘贴(在粘贴:):

     // Custom handling for rtfd type pasteboard data if let data = pb.dataForPasteboardType(rtfdStringType) { do { // Convert rtfd data to attributedString let attStr = try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSRTFDTextDocumentType], documentAttributes: nil) // Bonus: Possibly strip all unwanted attributes here. // Insert it into textview replaceSelection(attStr) return } catch {print("Couldn't convert pasted rtfd")} } // Default handling otherwise (plain-text) else { super.paste(sender) } 
  • 更好的方法是使用自定义的粘贴板types,将所有可能需要的标签进行白名单清理,然后将所有其他粘贴贴上。

  • (奖金:通过删除已添加的不必要的属性(如字体和fg-color),在其他应用程序中帮助UX)
  • 另外值得注意的是,textView可能不希望粘贴时,粘贴板包含一个特定的types,以解决:

     // Allow all sort of paste (might want to use a white list to check pb.items agains here) override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool { if action == #selector(UITextView.paste(_:)) { return true } return super.canPerformAction(action, withSender: sender) } 
  • 此外,切:也可以很好的执行。 基本上只是copy:replaceSelection(emptyString)

  • 为了您的方便:

     // Helper to insert attributed text at current selection/cursor position func replaceSelection(attributedString: NSAttributedString) { var selectedRange = self.selectedRange let m = NSMutableAttributedString(attributedString: self.attributedText) m.replaceCharactersInRange(self.selectedRange, withAttributedString: attributedString) selectedRange.location += attributedString.string.characters.count selectedRange.length = 0 self.attributedText = m self.selectedRange = selectedRange } 

祝你好运!

参考: 统一types标识符参考