I'm replacing emoji within a UILabel/UITextView with my own custom emoji. This works fine, but what I'm struggling with is getting the original emoji to paste.
So for example where the UILabel may display "Hello 😀", with a custom emoji, copying then pasting that text, or calling the text
property of the UILabel would display "Hello 😀" with the standard emoji.
I'm implementing this using a subclass of NSTextAttachment which displays an image, and adding it as an NSAttributedString whenever the emoji is used:
class EmojiTextAttachment: NSTextAttachment {
static let size = CGSize(width: 16, height: 16)
let emoji: Emoji
init(emoji: Emoji) {
self.emoji = emoji
super.init(data: emoji.rawValue.data(using: .utf8), ofType: "public.text")
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func image(forBounds imageBounds: CGRect, textContainer: NSTextContainer?, characterIndex charIndex: Int) -> UIImage? {
return Emoji.generateConstrainedFaceImage(emoji: emoji, height: imageBounds.size.height)
}
}
let emoji = Emoji(rawValue: emojiString)!
let emojiTextAttachment = EmojiTextAttachment(emoji: emoji)
emojiTextAttachment.bounds = CGRect(x: 0, y: self.font!.descender, width: self.font!.lineHeight, height: self.font!.lineHeight)
let attributedString = NSAttributedString(attachment: emojiTextAttachment)
This appears correctly, but now if I call the text
property of the UITextField, it doesn't include the NSTextAttachment as part of its' text. Additionally, copying the content copies the EmojiTextAttachment as data. Here, I've tried to set the data:ofType: to be a string (converted to data), but that didn't work, it just forms some data which is pated. And setting the image through emojiTextAttachment.image
means it'd paste the image. Setting it through the imageForBounds:textContainer:characterIndex:
function means the image itself doesn't get copied/pasted.
Is there a way that I can set the plaintext representation of an NSTextAttachment, or some other known way of making this work?
Couldn't find a really clean way of doing it. Subclassing NSAttributedString isn't supported, so no way of overriding the string
function.
Instead, I've added an extension of NSAttributedString with a plaintextRepresentation
function, which enumerates through the attributes, replacing any EmojiTextAttachments with the emoji itself, then returns the string
value of the attributed string.