How do you add an image attachment to an AttributedString?

2.2k views Asked by At

I'm working to replace NSAttributedString with AttributedString but have been unsuccessful in getting attachments to work. The image doesn't appear in the string despite the fact I applied the attachment.

let textAttachment = NSTextAttachment(image: UIImage(systemName: "exclamationmark.triangle.fill")!)
textAttachment.accessibilityLabel = "Warning"

// Original code
label.attributedText = NSAttributedString(attachment: textAttachment)

// New code
var attributedString = AttributedString()
attributedString.attachment = textAttachment
label.attributedText = NSAttributedString(attributedString)
1

There are 1 answers

0
Jordan H On BEST ANSWER

NSAttributedString(attachment:) magically creates an NSAttributedString with a single character (NSAttachmentCharacter which is U+FFFC OBJECT REPLACEMENT CHARACTER) and applies the text attachment attribute in order to replace that character with the image.

With the new AttributedString API you'll need to manually replicate that:

let textAttachment = NSTextAttachment(image: UIImage(systemName: "exclamationmark.triangle.fill")!)
textAttachment.accessibilityLabel = "Warning"

let attributedString = AttributedString("\(UnicodeScalar(NSTextAttachment.character)!)", attributes: AttributeContainer.attachment(textAttachment))

label.attributedText = NSAttributedString(attributedString)

Here's an example that replaces a substring with an image:

let addString = "+"
let string = "Tap \(addString) to add a task."
let addTextAttachment = NSTextAttachment(image: UIImage(systemName: "plus.square")!)

// NSAttributedString
label.attributedText = {
    let attributedString = NSMutableAttributedString(string: string)
    attributedString.replaceCharacters(in: (attributedString.string as NSString).range(of: addString), with: NSAttributedString(attachment: addTextAttachment))
    return attributedString
}()

// AttributedString
label.attributedText = {
    var attributedString = AttributedString(string)
    let attachmentString = AttributedString("\(UnicodeScalar(NSTextAttachment.character)!)", attributes: AttributeContainer.attachment(addTextAttachment))
    attributedString.replaceSubrange(attributedString.range(of: addString)!, with: attachmentString)
    return NSAttributedString(attributedString)
}()