user5899631
user5899631

Reputation:

Swift - NSMutableAttributedString changes all text in UITextView

Download an example I have created

Example Link

I am adding a link to my UITextView like this:

 let systemFont = self.text.font!
 let linkAttributes = [
          NSFontAttributeName : systemFont,
          NSLinkAttributeName: NSURL(string: alertController.textFields![0].text!)!] as [String : Any]

 let myAttributes2 = [ NSForegroundColorAttributeName: customGreen]

 let attributedString = NSMutableAttributedString(string: "\(urlName)")

 // Set the 'click here' substring to be the link
 attributedString.setAttributes(linkAttributes, range: NSMakeRange(0, urlName.characters.count))//(0, urlName.characters.count))

 self.text.linkTextAttributes = myAttributes2
 self.text.textStorage.insert(attributedString, at: self.text.selectedRange.location)

 let cursor = NSRange(location: self.text.selectedRange.location + "\(urlName)".characters.count, length: 0)
 self.text.selectedRange = cursor
 // self.text.font = systemFont

But after inserting it, it changes all the current text in the UITextView to the same font.

So for example if I have some text that is Bold and some more text that is Italic, after I add the url(which is system font) it resets all the bold/italic text to the system font....

If anyone knows how to keep the current font of the previous text I'd really appreciate the help.

For any further explanation just drop a comment below!

Many thanks in advance to anyone that can help!

Update

I am changing the text here in textDidChange

  if text == " " 
  {
       //      let systemFont = self.text.font!
       //    let linkAttributes = [NSFontAttributeName : systemFont]
       let attributes = [NSForegroundColorAttributeName: UIColor.black, NSFontAttributeName: self.text.font!] as [String : Any]

       let attributedString = NSMutableAttributedString(string: text, attributes: attributes)
       self.text.textStorage.insert(attributedString, at: range.location)
       let cursor = NSRange(location: self.text.selectedRange.location+1, length: 0)
       textView.selectedRange = cursor
       return false
 }

I have that so after adding the URL I make a space and reset the font so I don't continue typing as a URL link...Probably the problem but when I type normal and don't set a url link the text doesn't changing while make a space...

Upvotes: 8

Views: 4472

Answers (1)

J. Koush
J. Koush

Reputation: 1068

let urlName = "google"

@IBAction func btnPressed(_ sender: Any) {

   let systemFont = UIFont.systemFont(ofSize: 11)
   let linkAttributes = [
        NSFontAttributeName : systemFont,
        NSLinkAttributeName: NSURL(string: "https://www.google.com")!] as [String : Any]

   let myAttributes2 = [NSForegroundColorAttributeName: UIColor.green]

   let attributedString = NSMutableAttributedString(string: "\(urlName)")

   attributedString.setAttributes(linkAttributes, range: NSMakeRange(0, urlName.characters.count))//(0, urlName.characters.count))

   self.text.linkTextAttributes = myAttributes2
   self.text.textStorage.insert(attributedString, at: self.text.selectedRange.location)

   let cursor = NSRange(location: self.text.selectedRange.location + "\(urlName)".characters.count, length: 0) 
   self.text.selectedRange = cursor
}

This is how you should update the textView if you want to add text programmatically. Do not use the textViewDidChange(_:) delegate method in this situation.

UPDATE

I've downloaded your code from dropbox and made some changes to it. so here I'm changing the textView text in viewDidLoad() for example. I've created two constants in order to use them again in the code, fontAttr is the original font with the name and size and fontColorAttrBlue is the original font color.

let fontAttr = UIFont(name: "Helvetica-Bold", size: 20)
let fontColorAttrBlue = UIColor.blue

override func viewDidLoad() {
    super.viewDidLoad()

    let attrString = NSMutableAttributedString(string: "Hello World, How are you?", attributes: [NSFontAttributeName : fontAttr!, NSForegroundColorAttributeName: fontColorAttrBlue ])
    self.textView.delegate = self // you can set the delegate from the storyboard.
    self.textView.attributedText = attrString
}

And I've deleted this line of code self.textView.font = systemFont from webLink(_ sender: AnyObject) action method, so that it wouldn't change the font of the textView.

And lastly in textView(_:shouldChangeTextIn:replacementText:) method instead of checking if the user has entered " " String I'm checking if the user has entered any String and reusing the font attributes that I created in the beginning, so that if the user enters any kind of text after the link it would be the original text and not the one assigned for the like text.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    if text.characters.count > 0 {
        let attributedString = NSMutableAttributedString(string: text, attributes: [NSFontAttributeName : self.fontAttr!, NSForegroundColorAttributeName: self.fontColorAttrBlue])
        self.textView.textStorage.insert(attributedString, at: range.location)
        let cursor = NSRange(location: self.textView.selectedRange.location+1, length: 0)
        textView.selectedRange = cursor
        return false
    }
    return true
}

Upvotes: 4

Related Questions