How to add images to text attachment in Swift using nsattributedstring

I am trying to create a custom keyboard for iOS using the images that I entered as buttons. When I click the button, the image associated with the button is placed in the attribute string, which is loaded into the UiTextView inside the user-defined keyboard view. It works.

The problem is that when adding a new image to the attribute string, both old and new images in the string change to the image that I just clicked. I cannot understand why the old images in the line are changing.

Any suggestions? I tried using replaceCharactersInRange and insertAttributedString but cant get it working. Here is the code (after viewDidLoad):

let textAttachment = NSTextAttachment() let textView = UITextView(frame: CGRectMake(5, 5, 200, 40)) var attributedString = NSMutableAttributedString(string: "") @IBAction func buttonPressed(button :UIButton) { let string = button.titleLabel?.text textAttachment.image = UIImage(named: "\(string!).png")! textAttachment.image = UIImage(CGImage: textAttachment.image!.CGImage!, scale: 6, orientation: .Up) let attrStringWithImage = NSAttributedString(attachment: textAttachment) attributedString.appendAttributedString(attrStringWithImage); textView.attributedText = attributedString; } 

Thanks!

+8
ios iphone swift custom-keyboard ios-app-extension
source share
3 answers

We cannot just add an NSTextAttachment image . We must store all attached images and concatenation to existing String attributes.

 func buttonPressed(_ sender: Any) { let button = sender as! UIButton let tag = button.tag let attributedString:NSAttributedString! switch tag { case 2: attributedString = addAttributedText(text: (button.titleLabel?.text)!) case 3: attributedString = addAttributedText(text: (button.titleLabel?.text)!) case 4: attributedString = addAttributedText(text: (button.titleLabel?.text)!) default: attributedString = addAttributedText(text: "launch") } textView.attributedText = attributedString } func addAttributedText(text:String) -> NSAttributedString { textViewDidChange(textView) let axtractedImageAttribute = NSMutableAttributedString() for image in imageArray { let attachment:NSTextAttachment = NSTextAttachment() attachment.image = image attachment.setImageHeight(height: 20) let attachmentString:NSAttributedString = NSAttributedString(attachment: attachment) axtractedImageAttribute.append(attachmentString) } let attachment:NSTextAttachment = NSTextAttachment() attachment.image = UIImage(named: "\(text).png") attachment.setImageHeight(height: 20) let attachmentString:NSAttributedString = NSAttributedString(attachment: attachment) let attributedString:NSMutableAttributedString = NSMutableAttributedString(string:textView.text!) attributedString.append(axtractedImageAttribute) attributedString.append(attachmentString) return attributedString } //MARKS:- Extract attachedImage func textViewDidChange(_ textView: UITextView) { imageArray = [UIImage]() let range = NSRange(location: 0, length: textView.attributedText.length) if (textView.textStorage.containsAttachments(in: range)) { let attrString = textView.attributedText var location = 0 while location < range.length { var r = NSRange() let attrDictionary = attrString?.attributes(at: location, effectiveRange: &r) if attrDictionary != nil { let attachment = attrDictionary![NSAttachmentAttributeName] as? NSTextAttachment if attachment != nil { if attachment!.image != nil { imageArray.append( attachment!.image!) } } location += r.length } } } } } 

enter image description here enter image description here

Demo version

+3
source share

I found the problem, I need to have different variables for NSTextAttachment (i.e. textAttachment1, textAttachment2, etc.), otherwise it just uses the first drawn image.

0
source share

This works for me:

 let attributedStringTextAttachment = NSTextAttachment() attributedStringTextAttachment.image = UIImage(named: "image") 
0
source share

All Articles