5

New to Swift and iOS. I am attempting to allow the user to copy an nsattributedstring in my app and paste it into Mail, iMessage, or whatever app they choose.

@IBAction func action(sender: UIButton!) {

    let stringAttributes = [
        NSFontAttributeName: UIFont.boldSystemFontOfSize(14.0),
        NSBackgroundColorAttributeName: UIColor.redColor(),
    ]
    let attributedString = NSMutableAttributedString(string: "Hello world!", attributes: stringAttributes)

    do {
        let documentAttributes = [NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType]
        let rtfData = try attributedString.dataFromRange(NSMakeRange(0, attributedString.length), documentAttributes: documentAttributes)
        if let rtfString = String(data: rtfData, encoding: NSUTF8StringEncoding) {
            let pb = UIPasteboard.generalPasteboard()
            return pb.string = rtfString
        }
    }
    catch {
        print("error creating RTF from Attributed String")
    }
}

When pasted, this returns:

Hello world!{ NSBackgroundColor = "UIDeviceRGBColorSpace 1 0 0 1";NSFont = " font-family:\".SFUIText-Semibold\"; font-weight: bold; font-style: normal; font-size: 14.00pt"; }

Edited code returns:

{\rtf1\ansi\anscipg1252{fontal\f0\fnil\fcharset0 .SFUIText-Semibold;}{\colortbl;\red255\green255\blue255;\red255\green0\blue0;}\pard\tx560\tx1120\tx1680...\pardirnatural\partightenfactor0 \f0\b\fs28\cf0 Hello world!

While doing research, I came across this answer but was not able to get it to work from Leonard Pauli's response. Maybe because that's only within the app and not pasting to another? I'm sorry if this is a duplicate of this question. Paste Formatted Text, Not Images or HTML

I also could not translate this Copy Text with Formatting - iOS 6 NSAttributedString to Pasteboard to swift

I can paste plain text just not text with any attributes.

Community
  • 1
  • 1
sg1991
  • 51
  • 4
  • 1
    Right now, your copying the string description of a NSAttributedString object to the pasteboard. http://stackoverflow.com/questions/12601039/copy-nsattributedstring-in-uipasteboard may have a strategy that works for you, although it is a post in Objective-C. – cpimhoff Aug 24 '16 at 18:00
  • Thank you for the response. Would you use Guillaume or Ortwin Gentz answer? I came across this before and attempted Guillaume's answer with no luck. @cpimhoff – sg1991 Aug 25 '16 at 14:22
  • I have not tested either myself, but Ortwin's answer seems more practical to me. – cpimhoff Aug 25 '16 at 16:16
  • Any thoughts on update @cpimhoff – sg1991 Aug 31 '16 at 19:15
  • Your edited code creates the RTF data correctly (to my knowledge) but now you're saving a String description of the RTF Data object to the pasteboard. Much the same issue as earlier. You'll need to use add the RTF data to the pasteboard properly (as a dictionary with the key being the data type). I'll update your code and will post an answer shortly. – cpimhoff Aug 31 '16 at 20:25

2 Answers2

4

for swift 5

func copyAttributedStringToPB() {

        let stringAttributes = [
            NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 14.0),
            NSAttributedString.Key.backgroundColor: UIColor.red,
        ]
        let attributedString = NSMutableAttributedString(string: "Hello world!", attributes: stringAttributes)

        do {
            let documentAttributes = [NSAttributedString.DocumentAttributeKey.documentType: NSAttributedString.DocumentType.rtf]
            let rtfData = try attributedString.data(from: NSMakeRange(0, attributedString.length), documentAttributes: documentAttributes)
            let pb = UIPasteboard.general
            pb.setData(rtfData, forPasteboardType: kUTTypeRTF as String)
        }
        catch {
            print("error creating RTF from Attributed String")
        }
    }
Grenoblois
  • 503
  • 1
  • 5
  • 19
3

I've updated your code to save the RTF data you're creating to the pasteboard properly, however, loading the RTF data and placing it back into a NSAttributedString object, seems to be a manual task.

As such, the copy and paste behavior will only work in contexts where the developer has explicitly supported the copying and pasting of RTF data in this manner.

Unfortunately, in the Playgrounds I've been testing the code in, the Pasteboard's string property is set to contain the plaintext version of the RTF data (which is full of markup and weird control characters). I haven't been able to find a solution which fixes this issue, which means apps which don't support the RTF in this manner may still paste the marked up RTF plaintext, instead of attributed text... :(

This will get you some of the way there (in app copy-paste RTF) but obviously isn't great. My projects also rely on this kind of behavior, so if anybody has additional ideas, I'd also love to know.

import MobileCoreServices

   // ----- Copy ------ 
func copyAttributedStringToPB() {

    let stringAttributes = [
        NSFontAttributeName: UIFont.boldSystemFontOfSize(14.0),
        NSBackgroundColorAttributeName: UIColor.redColor(),
    ]
    let attributedString = NSMutableAttributedString(string: "Hello world!", attributes: stringAttributes)

    do {
        let documentAttributes = [NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType]
        let rtfData = try attributedString.dataFromRange(NSMakeRange(0, attributedString.length), documentAttributes: documentAttributes)
        let pb = UIPasteboard.generalPasteboard()
        pb.setData(rtfData, forPasteboardType: kUTTypeRTF as String)
    }
    catch {
        print("error creating RTF from Attributed String")
    }
}

  // -------- Paste -------
let pb = UIPasteboard.generalPasteboard()
let data = pb.dataForPasteboardType(kUTTypeRTF as String)

let pastedAttributedString = try! NSAttributedString(data: data!, options: [NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType], documentAttributes: nil)
cpimhoff
  • 675
  • 6
  • 11
  • This gives the error "contextual type 'AnyObject' cannot be used with dictionary literal" on the pb.items line. Working on a solution @cpimhoff – sg1991 Sep 02 '16 at 12:58
  • Sorry. Ive been away from a compiler for a while... dependent on your Swift version, you may also need to convert `kUTTypeRYF` and `kUTTypeUTF8PlainText` to a Swift String. – cpimhoff Sep 02 '16 at 19:03
  • Thanks for the response. Casting as string returns the same thing as the edited code above unfortunately. – sg1991 Sep 06 '16 at 14:23
  • After much playing around in Playgrounds, I've come to the solution above -- which doesn't particularly solve your problem (and I apologize deeply). – cpimhoff Sep 07 '16 at 12:31
  • Explicit support from developer has been my hangup but I appreciate your effort. I recently found an app (custom keyboard) called Color Text that seems to have similar functionality to my question. I think the developers approach may use an image but i haven't been able to reproduce it. – sg1991 Sep 07 '16 at 13:39