NSAttributedString get images and string in parts - swift

I have an NSAttributedString with a mixture of String and NSTextAttachment with images in there. How would I extract an [AnyObject] array of the parts?

This worked for me in Swift 4:
extension UITextView {
func getParts() -> [AnyObject] {
var parts = [AnyObject]()
let attributedString = self.attributedText
let range = NSMakeRange(0, attributedString.length)
attributedString.enumerateAttributes(in: range, options: NSAttributedString.EnumerationOptions(rawValue: 0)) { (object, range, stop) in
if object.keys.contains(NSAttributedStringKey.attachment) {
if let attachment = object[NSAttributedStringKey.attachment] as? NSTextAttachment {
if let image = attachment.image {
parts.append(image)
} else if let image = attachment.image(forBounds: attachment.bounds, textContainer: nil, characterIndex: range.location) {
parts.append(image)
}
}
} else {
let stringValue : String = attributedString.attributedSubstring(from: range).string
if (!stringValue.trimmingCharacters(in: .whitespaces).isEmpty) {
parts.append(stringValue as AnyObject)
}
}
}
return parts
}

I figured it out you can iterate over all the attributedString and read if the object has an NSTextAttachmentAttributeName property. If not, assume it's a string.
extension UITextView {
func getParts() -> [AnyObject] {
var parts = [AnyObject]()
let attributedString = self.attributedText
let range = NSMakeRange(0, attributedString.length)
attributedString.enumerateAttributesInRange(range, options: NSAttributedStringEnumerationOptions(rawValue: 0)) { (object, range, stop) in
if object.keys.contains(NSAttachmentAttributeName) {
if let attachment = object[NSAttachmentAttributeName] as? NSTextAttachment {
if let image = attachment.image {
parts.append(image)
}else if let image = attachment.imageForBounds(attachment.bounds, textContainer: nil, characterIndex: range.location) {
parts.append(image)
}
}
}else {
let stringValue : String = attributedString.attributedSubstringFromRange(range).string
if !stringValue.isEmptyOrWhitespace() {
parts.append(stringValue)
}
}
}
return parts
}
}

Related

How to check if text is underlined

I am struggling to determine if some selected text in a UITextView is underlined. I can quite easily check for bold, italics etc with the following code:
let isItalic = textView.font!.fontDescriptor.symbolicTraits.contains(.traitItalic)
However, I can't figure out how to check for underline?
I have just created a sample project and I think you could do something like the following:
class ViewController: UIViewController {
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let attrText1 = NSMutableAttributedString(string: "TestTest", attributes: [.foregroundColor : UIColor.systemTeal, .underlineStyle: NSUnderlineStyle.single.rawValue])
let attrText2 = NSAttributedString(string: " - not underlined", attributes: [.foregroundColor : UIColor.red])
attrText1.append(attrText2)
textView.attributedText = attrText1
}
func isTextUnderlined(attrText: NSAttributedString?, in range: NSRange) -> Bool {
guard let attrText = attrText else { return false }
var isUnderlined = false
attrText.enumerateAttributes(in: range, options: []) { (dict, range, value) in
if dict.keys.contains(.underlineStyle) {
isUnderlined = true
}
}
return isUnderlined
}
#IBAction func checkButtonDidTap(_ sender: UIButton) {
print(isTextUnderlined(attrText: textView.attributedText, in: textView.selectedRange))
}
}
Create an extension to get the selectedRange as NSRange:
extension UITextInput {
var selectedRange: NSRange? {
guard let range = selectedTextRange else { return nil }
let location = offset(from: beginningOfDocument, to: range.start)
let length = offset(from: range.start, to: range.end)
return NSRange(location: location, length: length)
}
}
I believe underline is not part of the font traits, it must rather be an attribute to the text. You might find the answer to this question useful. I hope it helps you! Enumerate over a Mutable Attributed String (Underline Button)
func checkForUnderline(){
let allWords = self.testView.text.split(separator: " ")
for word in allWords {
let result = self.isLabelFontUnderlined(textView: self.testView,
subString: word as NSString)
if(result == true){
print(word+" is underlined")
}else{
print(word+" is not underlined")
}
}
}
func isLabelFontUnderlined (textView: UITextView, subString:
NSString) -> Bool {
let nsRange = NSString(string: textView.text).range(of: subString as
String, options: String.CompareOptions.caseInsensitive)
if nsRange.location != NSNotFound {
return self.isLabelFontUnderlined(textView: textView,
forRange: nsRange)
}
return false
}
func isLabelFontUnderlined (textView: UITextView, forRange: NSRange) ->
Bool{
let attributedText = testView.attributedText!
var isRangeUnderline = false
attributedText.enumerateAttributes(in: forRange,
options:.longestEffectiveRangeNotRequired) { (dict, range, value) in
if dict.keys.contains(.underlineStyle) {
if (dict[.underlineStyle] as! Int == 1){
isRangeUnderline = true
} else{
isRangeUnderline = false
}
}else{
isRangeUnderline = false
}
}
return isRangeUnderline
}

How to save an UIButton image using UserDefaults?

I want to save an UIButton image inside UserDefaults and retrieve it with a key later on in my code. The UIImage comes from a tuple that is being used by an UIPickerView.
let defaults = UserDefaults.standard
#IBOutlet weak var topCurrencyPicker: UIPickerView!
var topPickerOptions = [
(symbol: String, name: String, sign: String, flag: UIImage)]()
func createTopAndBottomCurrency() {
let topUserIndex = topCurrencyPicker.selectedRow(inComponent: 0)
let topUserChoice = money.currencyISOCode[topUserIndex]
userCurrencyChoice = Currencies(top: topUserChoice, bottom: bottomUserChoice)
// Save user pickerViews Choice
defaults.set(topUserIndex,
forKey: ExchangePreferencesVC.topExPickerKey)
defaults.set(userCurrencyChoice.top.sign,
forKey: ExchangePreferencesVC.topExSignKey)
defaults.set(userCurrencyChoice.top.symbol,
forKey: ExchangePreferencesVC.topExSymbolKey)
}
Is it then possible to save this UIImage as easily as a String can be?
Swift 4.2
public final class PreferencesService {
private let userDefaults: UserDefaults
init(userDefaults: UserDefaults = .standard) {
self.userDefaults = userDefaults
}
var avatar: UIImage? {
get {
guard let filename = documentsDirectory?.appendingPathComponent(#function, isDirectory: false) else {
return nil
}
return UIImage(contentsOfFile: filename.path)
}
set {
guard let filename = documentsDirectory?.appendingPathComponent(#function, isDirectory: false) else {
return
}
guard let newImage = newValue else {
try? FileManager.default.removeItem(at: filename)
return
}
if let data = newImage.jpegData(compressionQuality: 1.0) {
try? data.write(to: filename)
}
}
}
private var documentsDirectory: URL? {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths.first
}
var coolDown: Bool {
get { return userDefaults.bool(forKey: #function) }
set { userDefaults.set(newValue, forKey: #function) }
}
var lastVisited: Date {
get { return userDefaults.object(forKey: #function) as? Date ?? Date() }
set { userDefaults.set(newValue, forKey: #function) }
}
}
Better to store image in Document Directory.
If needed to Store UserDefaults - you can store it like Data.
Usage
PreferencesService().avatar = button.image(for: .normal)
Bonus: Note how to store simply other types Bool, Date, String.

swift extract hashtag strings from text

How do I extract hashtag strings from a text in Swift? I've seen some answers but they seem too complicated for what I need and I don't really understand how RegEx works?
E.g.
Text: "This is #something with a lot of #random #hashtags #123yay."
What I want: "something", "random", "hashtags", "123yay".
Thanks!
here is the helper method to convert your string into hash detection string
this extension find the # words from sting also including arabic words.
extension String {
func findMentionText() -> [String] {
var arr_hasStrings:[String] = []
let regex = try? NSRegularExpression(pattern: "(#[a-zA-Z0-9_\\p{Arabic}\\p{N}]*)", options: [])
if let matches = regex?.matches(in: self, options:[], range:NSMakeRange(0, self.count)) {
for match in matches {
arr_hasStrings.append(NSString(string: self).substring(with: NSRange(location:match.range.location, length: match.range.length )))
}
}
return arr_hasStrings
}
}
And below method converts your string into Reach colorful hash string.
func convert(_ hashElements:[String], string: String) -> NSAttributedString {
let hasAttribute = [NSAttributedStringKey.foregroundColor: UIColor.orange]
let normalAttribute = [NSAttributedStringKey.foregroundColor: UIColor.black]
let mainAttributedString = NSMutableAttributedString(string: string, attributes: normalAttribute)
let txtViewReviewText = string as NSString
hashElements.forEach { if string.contains($0) {
mainAttributedString.addAttributes(hasAttribute, range: txtViewReviewText.range(of: $0))
}
}
return mainAttributedString
}
i.e
let text = "#Jaydeep #Viral you have to come for party"
let hashString = convert(text.findMentionText(), string: text)
Output:
extension String
{
func hashtags() -> [String]
{
if let regex = try? NSRegularExpression(pattern: "#[a-z0-9]+", options: .caseInsensitive)
{
let string = self as NSString
return regex.matches(in: self, options: [], range: NSRange(location: 0, length: string.length)).map {
string.substring(with: $0.range).replacingOccurrences(of: "#", with: "").lowercased()
}
}
return []
}
}
then, to get the hashtags array
yourstring.hashtags()
Here is the source
let str = "This is #something with a lot of #random #hashtags #123yay."
let words = str.components(separatedBy: " ")
var hashTags = [String]()
for word in words{
if word.hasPrefix("#"){
let hashtag = word.dropFirst()
hashTags.append(String(hashtag))
}
}
print("Hashtags :: ", hashTags)
First things first, this works best in a TextView. So set one up inside of your view however you want, but make sure that your ViewController has a UITextViewDelegate & the textView is delegated to that view controller.
I’m also doing this with some prefilled information, but the same concept applies with pulling data from your database and what not.
This is how we set up our ViewController:
class ViewController: UIViewController, UITextViewDelegate {
var string = "Hello, my name is #Jared & #Jared and I like to move it."
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
textView.text = string
textView.delegate = self
}
The overall task we’re trying to accomplish in this part is just to split up all the words in our textView. It’s simpler than you might think:
First, let’s create our extension:
Now add this to your ViewController:
extension UITextView {
func resolveTags(){
let nsText:NSString = self.text as NSString
let words:[String] = nsText.components(separatedBy: " ")
let attrs = [
NSAttributedStringKey.font : UIFont.init(name: "HelveticaNeue", size: 13),
NSAttributedStringKey.foregroundColor : UIColor.black
]
let attrString = NSMutableAttributedString(string: nsText as String, attributes:attrs)
for word in words {
if word.hasPrefix("#") {
let matchRange:NSRange = nsText.range(of: word as String)
var stringifiedWord:String = word as String
stringifiedWord = String(stringifiedWord.dropFirst())
attrString.addAttribute(NSAttributedStringKey.link, value: "hash:\(stringifiedWord)", range: matchRange)
attrString.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.blue , range: matchRange)
}
}
self.attributedText = attrString
}
}
Let’s use this thing!
It all comes down to this. We have this function working, now how do we use it?
Easy.
Inside of your viewDidLoad function, or wherever you set your textView text, just call:
textView.resolveTags()
Result:
Courtesy of: Jared Davidson On Twitter
You can also use third party Activelabel . this is simple to use and also support Hashtags (#), Mentions (#), URLs (http://) and custom regex patterns
https://github.com/optonaut/ActiveLabel.swift
I just changed #JayDeep 's answer to more swifty style.
extension String {
var tags: [String] {
let regex = try? NSRegularExpression(pattern: "(#[a-zA-Z0-9_\\p{Arabic}\\p{N}]*)", options: [])
let nsRange: NSRange = .init(location: 0, length: self.count)
guard let matches = regex?.matches(in: self, options: NSRegularExpression.MatchingOptions(), range: nsRange)
else { return [] }
return matches
.map { match in
let startIndex = self.index(self.startIndex, offsetBy: match.range.location)
let endIndex = self.index(startIndex, offsetBy: match.range.length)
let range = startIndex ..< endIndex
return String(self[range])
}
}
}
My clean solution: We will return PrefixesDetected to the view. And the view will format it as he wants. (So we will execute yourString.resolvePrefixes()) in the viewModel and we will be able to test it.
struct PrefixesDetected {
let text: String
let prefix: String?
}
extension String {
func resolvePrefixes(_ prefixes: [String] = ["#", "#"]) -> [PrefixesDetected] {
let words = self.components(separatedBy: " ")
return words.map { word -> PrefixesDetected in
PrefixesDetected(text: word,
prefix: word.hasPrefix(prefixes: prefixes))
}
}
func hasPrefix(prefixes: [String]) -> String? {
for prefix in prefixes {
if hasPrefix(prefix) {
return prefix
}
}
return nil
}
}
Then in the view we can format it as for example: (In this case we want both in the same color but in this way you can give them different behaviors)
Here I do with reduce but this is just to show an example, you can format it as you want! :)
titleDetectedPrefixes.reduce(NSAttributedString(), { result, prefixDectedWord in
let wordColor: UIColor = prefixDectedWord.prefix != nil ? .highlightTextMain : .mainText
let attributedWord = NSAttributedString(string: prefixDectedWord.text)
{ Add desired attributes }
})
for those who are using swiftUI you can achieve it by using the "+" operator
so the final solution will look like this
static func tagHighlighter(description : String , previousText : Text = Text("") , tag : String = "#") -> Text {
var t : Text = Text("")
let words : [String] = description.components(separatedBy: " ")
for word in words {
if !word.isEmpty {
let tag = word[word.startIndex]
if tag == "#" {
t = t + Text("\(word) ").foregroundColor(Color("tag_color"))
} else if tag == "#" {
t = t + Text("\(word) ").foregroundColor(Color("tag_color"))
} else {
t = t + Text("\(word) ")
}
}
}
return t
}
This is how I'm doing it
private func getHashTags(from caption: String) -> [String] {
var words: [String] = []
let texts = caption.components(separatedBy: " ")
for text in texts.filter({ $0.hasPrefix("#") }) {
if text.count > 1 {
let subString = String(text.suffix(text.count - 1))
words.append(subString.lowercased())
}
}
return words
}
Copy paste this extension to your class:
extension UITextView{
func insertTextWithHashtags(text textString: String){
let nsTextString: NSString = textString as NSString
let simpleTextAttributes: [NSAttributedString.Key : Any] = [NSAttributedString.Key.foregroundColor : UIColor(named: "Black Color")!, NSAttributedString.Key.font : UIFont(name: "Inter-Regular", size: 16.0)!]
let attributedString = NSMutableAttributedString(string: textString, attributes: simpleTextAttributes)
var word = ""
for text in textString+" "{ //+" " is for loop to run one extra time to complete hashtag
if text == "#" || text == "\n" || text == " "{
if word.hasPrefix("#"){
let range = nsTextString.range(of: word)
let link = [NSAttributedString.Key.link : word]
attributedString.addAttributes(link, range: range)
if text == "#"{
word = "#"
}else{
word = ""
}
}else{
if text == "#"{
word = "#"
}
}
}else{
if word.hasPrefix("#"){
word.append(text)
}
}
}
//For for applying attributes to hashtag
let linkAttributes: [NSAttributedString.Key : Any] = [NSAttributedString.Key.foregroundColor : UIColor(named: "Primary Color")!]
self.linkTextAttributes = linkAttributes
self.attributedText = attributedString
}
}
and then call it like this:
postTextView.insertTextWithHashtags(text: "#Hello#Hey #Space")

replace NSTextAttachment that include an image to String

Before, I changed specific strings to NSTextAttachment that include image to display custom emoticon.
String to NSTextAttachment code
{
guard
let original = self.attributedText
else { return }
let pattern = "\\[img src=(\\w+)\\]"
do{
let regex = try NSRegularExpression(pattern: pattern, options: [])
let matches = regex.matches(in: original.string, options : [], range : NSMakeRange(0, original.string.characters.count))
let attributeString = NSMutableAttributedString(attributedString: original)
for match in matches.reversed(){
let emoticonString = attributeString.attributedSubstring(from: match.rangeAt(1)).string
if let emoticonAndroid = Emoticon(rawValue: emoticonString),
let image = UIImage(named : "\(emoticonAndroid.convertFromAndroid().rawValue)_000"){
image.accessibilityIdentifier = emoticonAndroid.rawValue
let attributedImage = NSTextAttachment()
attributedImage.image = image
attributedImage.bounds = CGRect(x: 0, y: -8, width: 25, height: 25)
attributeString.beginEditing()
attributeString.replaceCharacters(in: match.rangeAt(0), with: NSAttributedString(attachment: attributedImage))
attributeString.endEditing()
}
}
self.attributedText = attributeString
}catch{
return
}
}
but, I need to replace NSTextAttachment to string to send message.
I used NSMutableAttributedString.replaceCharacters(in:with:) method. but, It can work with only one emoticon image.
one emoticon
two emoticons or more
how can I fix it?
NSTextAttachment to String code
{
if let original = self.attributedText{
let attributeString = NSMutableAttributedString(attributedString: original)
original.enumerateAttribute(NSAttachmentAttributeName, in: NSMakeRange(0, original.length), options: [], using: { attribute, range, _ in
if let attachment = attribute as? NSTextAttachment,
let image = attachment.image{
let str = "[img src=\(image.accessibilityIdentifier!)]"
attributeString.beginEditing()
attributeString.(in: range, with: str)
attributeString.endEditing()
}
})
self.attributedText = attributeString
return attributeString.string
}else{
return nil
}
}
Umm.. I solved this problem.
First : Count number of NSTextAttachment
var count = 0
self.attributedText.enumerateAttribute(NSAttachmentAttributeName, in : NSMakeRange(0, self.attributedText.length), options: [], using: { attribute, range, _ in
if let attachment = attribute as? NSTextAttachment,
let image = attachment.image{
count = count + 1
}
})
return count
Second : Replace NSTextAttachment with String and calculate the changed range. <- Repeat
for i in 0..<self.countOfNSTextAttachment(){
let attributedString = NSMutableAttributedString(attributedString: self.attributedText)
var count = 0
attributedString.enumerateAttribute(NSAttachmentAttributeName, in : NSMakeRange(0, attributedString.length), options: [], using: { attribute, range, _ in
if let attachment = attribute as? NSTextAttachment,
let image = attachment.image{
let str = "[img src=\(image.accessibilityIdentifier!)]"
if count == 0{
attributedString.beginEditing()
attributedString.replaceCharacters(in: range, with: NSAttributedString(string : str))
attributedString.endEditing()
self.attributedText = attributedString
}else{
return
}
count = count + 1
}
})
}
return self.attributedText.string
Result : result
Perfect!!

How do I insert an image Inline UILabel in iOS 8 using swift

I followed the following post on how to use NSTextAttachment to add images inline with your UILabels. I followed the best I could and wrote my version in Swift.
I am creating a chat application and the field that I'm inserting a beer icon into does not render the image or doesn't seem to render the image inline. I don't get any errors so I'm assuming I'm missing some small little detail in my code.
var beerName:String!
if(sender == bn_beer1)
{
beerName = "beer1.png"
}
if(sender == bn_beer2)
{
beerName = "beer2.png"
}
if(sender == bn_beer3)
{
beerName = "beer3"
}
var attachment:NSTextAttachment = NSTextAttachment()
attachment.image = UIImage(named: beerName)
var attachmentString:NSAttributedString = NSAttributedString(attachment: attachment)
var myString:NSMutableAttributedString = NSMutableAttributedString(string: inputField.text)
myString.appendAttributedString(attachmentString)
inputField.attributedText = myString;
This does not work on a UITextField. It only works on a UILabel.
Here is a UILabel extension based on your code (Swift 2.0)
extension UILabel
{
func addImage(imageName: String)
{
let attachment:NSTextAttachment = NSTextAttachment()
attachment.image = UIImage(named: imageName)
let attachmentString:NSAttributedString = NSAttributedString(attachment: attachment)
let myString:NSMutableAttributedString = NSMutableAttributedString(string: self.text!)
myString.appendAttributedString(attachmentString)
self.attributedText = myString
}
}
EDIT:
here is a new version that allow to add the icon before or after the label. There is also a function to remove the icon from the label
extension UILabel
{
func addImage(imageName: String, afterLabel bolAfterLabel: Bool = false)
{
let attachment: NSTextAttachment = NSTextAttachment()
attachment.image = UIImage(named: imageName)
let attachmentString: NSAttributedString = NSAttributedString(attachment: attachment)
if (bolAfterLabel)
{
let strLabelText: NSMutableAttributedString = NSMutableAttributedString(string: self.text!)
strLabelText.appendAttributedString(attachmentString)
self.attributedText = strLabelText
}
else
{
let strLabelText: NSAttributedString = NSAttributedString(string: self.text!)
let mutableAttachmentString: NSMutableAttributedString = NSMutableAttributedString(attributedString: attachmentString)
mutableAttachmentString.appendAttributedString(strLabelText)
self.attributedText = mutableAttachmentString
}
}
func removeImage()
{
let text = self.text
self.attributedText = nil
self.text = text
}
}
Regis St-Gelais's extension answer for Swift 3 and Swift 4 and without forced unwrapping:
extension UILabel {
func addImageWith(name: String, behindText: Bool) {
let attachment = NSTextAttachment()
attachment.image = UIImage(named: name)
let attachmentString = NSAttributedString(attachment: attachment)
guard let txt = self.text else {
return
}
if behindText {
let strLabelText = NSMutableAttributedString(string: txt)
strLabelText.append(attachmentString)
self.attributedText = strLabelText
} else {
let strLabelText = NSAttributedString(string: txt)
let mutableAttachmentString = NSMutableAttributedString(attributedString: attachmentString)
mutableAttachmentString.append(strLabelText)
self.attributedText = mutableAttachmentString
}
}
func removeImage() {
let text = self.text
self.attributedText = nil
self.text = text
}
}
Usage:
self.theLabel.text = "desiredText"
self.theLabel.addImageWith(name: "nameOfImage", behindText: false)
Edit 19/03/18 : Correct bug when imageBehindText = false + Image size in pixel no point.
David's function update for multiple images with text saving and image size based on font size (Swift 4) :
extension UILabel {
/**
This function adding image with text on label.
- parameter text: The text to add
- parameter image: The image to add
- parameter imageBehindText: A boolean value that indicate if the imaga is behind text or not
- parameter keepPreviousText: A boolean value that indicate if the function keep the actual text or not
*/
func addTextWithImage(text: String, image: UIImage, imageBehindText: Bool, keepPreviousText: Bool) {
let lAttachment = NSTextAttachment()
lAttachment.image = image
// 1pt = 1.32px
let lFontSize = round(self.font.pointSize * 1.32)
let lRatio = image.size.width / image.size.height
lAttachment.bounds = CGRect(x: 0, y: ((self.font.capHeight - lFontSize) / 2).rounded(), width: lRatio * lFontSize, height: lFontSize)
let lAttachmentString = NSAttributedString(attachment: lAttachment)
if imageBehindText {
let lStrLabelText: NSMutableAttributedString
if keepPreviousText, let lCurrentAttributedString = self.attributedText {
lStrLabelText = NSMutableAttributedString(attributedString: lCurrentAttributedString)
lStrLabelText.append(NSMutableAttributedString(string: text))
} else {
lStrLabelText = NSMutableAttributedString(string: text)
}
lStrLabelText.append(lAttachmentString)
self.attributedText = lStrLabelText
} else {
let lStrLabelText: NSMutableAttributedString
if keepPreviousText, let lCurrentAttributedString = self.attributedText {
lStrLabelText = NSMutableAttributedString(attributedString: lCurrentAttributedString)
lStrLabelText.append(NSMutableAttributedString(attributedString: lAttachmentString))
lStrLabelText.append(NSMutableAttributedString(string: text))
} else {
lStrLabelText = NSMutableAttributedString(attributedString: lAttachmentString)
lStrLabelText.append(NSMutableAttributedString(string: text))
}
self.attributedText = lStrLabelText
}
}
func removeImage() {
let text = self.text
self.attributedText = nil
self.text = text
}
}
Use these below extension it will work for sure
extension NSMutableAttributedString {
static func addImageInBetweenString(firstSentence: String, image: UIImage?, lastSentence: String) -> NSMutableAttributedString {
// create an NSMutableAttributedString that we'll append everything to
let fullString = NSMutableAttributedString(string: firstSentence)
// create our NSTextAttachment
let image1Attachment = NSTextAttachment()
image1Attachment.image = image
//image1Attachment.setImageHeight(height: 15.0)
Image1Attachment.bounds = CGRect(x: 0, y: -5, width: 15, height: 15)
// wrap the attachment in its own attributed string so we can append it
let image1String = NSAttributedString(attachment: image1Attachment)
// add the NSTextAttachment wrapper to our full string, then add some more text.
fullString.append(image1String)
fullString.append(NSAttributedString(string: lastSentence))
return fullString
}
}
extension NSTextAttachment {
func setImageHeight(height: CGFloat) {
guard let image = image else { return }
let ratio = image.size.width / image.size.height
bounds = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: ratio * height, height: height)
}
}