Shubham
Shubham

Reputation: 818

How to set a style for a specific word inside UITextView?

I have a UITextView in which I am trying to style a particular word. The problem I am facing is that on setting a style for the word, it's also applying the style to all the other occurrences of the word. I just want one particular instance of the word say first or third to have the custom style.

Consider the text present inside UITextView.

Sunset is the time of day when our sky meets the outer space solar winds. 
There are blue, pink, and purple swirls, spinning and twisting, like clouds of balloons caught in
a whirlwind. The sun moves slowly to hide behind the line of horizon, while the 
moon races to take its place in prominence atop the night sky. People slow to a crawl, 
entranced, fully forgetting the deeds that must still be done. There is a coolness, a 
calmness, when the sun does set.

If I set the style to sun then both the occurrences of the word is getting the style applied.

Here is the code

let normalAttr = [NSAttributedString.Key.font: UIFont(name: "Oswald", size: 19.0), NSAttributedString.Key.paragraphStyle : style]
let customAttr = [NSAttributedString.Key.font: UIFont(name: "Oswald", size: 19.0), NSAttributedString.Key.foregroundColor: UIColor.red]
let words = textView.text.components(separatedBy: " ")
let newText = NSMutableAttributedString()
for word in words {
   if (word == selectedWord) {
     newText.append(NSMutableAttributedString(string: word + " " , attributes: selectedAttributes as [NSAttributedString.Key : Any]))
   } else {
     newText.append(NSMutableAttributedString(string:word + " ", attributes: normalAttributes as [NSAttributedString.Key : Any]))
   }
 }
textView.attributedText = newText

I just want to apply the style to one word any help on how could I do that?

Upvotes: 0

Views: 101

Answers (1)

gadu
gadu

Reputation: 1826

How are you choosing which instance to replace?

The simplest way to do this would be to just maintain your own counter:

var counter = 0
for word in words {
   if (word == selectedWord) {
     counter += 1
      // myTarget being the first or third or whatever
     let attributesToUse = (counter == myTarget) ? selectedAttributes : normalAttributes
     newText.append(NSMutableAttributedString(string: word + " " , attributes: attributesToUse as [NSAttributedString.Key : Any]))
   } else {
     newText.append(NSMutableAttributedString(string:word + " ", attributes: normalAttributes as [NSAttributedString.Key : Any]))
   }
 }

But you can certainly get cleaner by using NSAttributedStrings and looking for the range of your text..

let myText = NSMutableAttributedString(string: textView.text, attributes: normalAttributes)

// this will only turn up the FIRST occurrence
if let range = myText.range(of: selectedWord) {
    let rangeOfSelected = NSRange(range, in: myText)
    myText.setAttributes(selectedAttributes, range: rangeOfSelected)
}

If you want to use arbitrary occurrence you can prob write an extension that creates an array of all the ranges and then pick the one that matters, this is a good reference for that: https://medium.com/@weijentu/find-and-return-the-ranges-of-all-the-occurrences-of-a-given-string-in-swift-2a2015907a0e

Def could be overkill though, you can also modify the methods in those article to instead to take in an int (occuranceNumber) and use a counter like above to return only the range of the nth occurrence, and then do the same thing with attributed strings.

Upvotes: 1

Related Questions