Multiple range on NSMutableAttributedString - ios

i'm trying to set bold font two different string range in a string. I know how to do it range by range but is it possible to do it one time with multiple range. I don't like to repeat code.
Here's my code
if let rankString = trophy.fullRank.value {
var secondRankString = "some string"
var string = SRUtils.LocalizedString("unlocked.description", comment: "")
string = String(format: string, trophy.trophiesNumber.value!, rankString)
let atStr = NSMutableAttributedString(string: string)
//Here i need to add rankString and other range
let textRange = (string as NSString).range(of: rankString)
if let font = UIFont(name: "HelveticaNeue-Bold", size: 16) {
atStr.addAttribute(NSFontAttributeName, value: font, range: textRange)
self.trophyDescription.value = atStr
}
}
If for example:
var string = "Hello do you need a cat"
var rankString = "cat"
Result with my code: "Hello do you need a cat"
What i need it's :
var mytring = "Hello do you need a cat"
var rankString = "cat"
var secondRankString = "need"
Excepted result : "Hello do you need a cat"
So how i can, in swift 3, add multiple range to apply, without multiple declaration of variable... is it possible ?

two or more, use a for — Edsger W. Dijkstra
This code
import UIKit
let string = "Hello do you need a cat"
let attributedString = NSMutableAttributedString(string: string)
if let font = UIFont(name: "HelveticaNeue", size: 16) {
attributedString.addAttribute(NSFontAttributeName, value: font, range: NSRange(location:0, length: string.characters.count))
}
let highlightedWords = ["cat", "need"]
for highlightedWord in highlightedWords {
let textRange = (string as NSString).range(of: highlightedWord)
if let font = UIFont(name: "HelveticaNeue-Bold", size: 16) {
attributedString.addAttribute(NSFontAttributeName, value: font, range: textRange)
}
}
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
label.attributedText = attributedString
label.sizeToFit()
results in
i was just searching an other way to do it without for or multiple declaration
A for loop can always be expressed as a more generell while loop. But I find for loops easier to understand.
var highlightedWords = ["cat", "need"]
repeat {
if let highlightedWord = highlightedWords.popLast() {
let textRange = (string as NSString).range(of: highlightedWord)
if let font = UIFont(name: "HelveticaNeue-Bold", size: 16) {
attributedString.addAttribute(NSFontAttributeName, value: font, range: textRange)
}
}
} while highlightedWords.count > 0

Related

Adjust Elements after Manipulating String into AttributedString - Swift 4

I have the following which allows me to create a bullet list which works really well, however, after the bullet list is created I need to manipulate the outputted Attributed string to have certain elements either in bold or in italics or both.
The function I have is:
#IBOutlet var label: UILabel!
let bulletString = ["String 1","String 2","String 3"]
label.attributedText = label.bulletPoints(stringList: bulletString, font: UIFont.stdFontMediumSeventeen, bullet: "•", lineSpacing: 4, paragraphSpacing: 4, textColor: UIColor.darkGreyColor, bulletColor: UIColor.darkGreyColor)
func bulletPoints(stringList: [String],font: UIFont,bullet: String = "\u{2022}",indentation: CGFloat = 20,lineSpacing: CGFloat = 2,paragraphSpacing: CGFloat = 12,textColor: UIColor = .gray,bulletColor: UIColor = .red) -> NSAttributedString{
let textAttributes: [NSAttributedStringKey: Any] = [NSAttributedStringKey.font: font, NSAttributedStringKey.foregroundColor: textColor]
let bulletAttributes: [NSAttributedStringKey: Any] = [NSAttributedStringKey.font: font, NSAttributedStringKey.foregroundColor: bulletColor]
let paragraphStyle = NSMutableParagraphStyle()
let nonOptions = [NSTextTab.OptionKey: Any]()
paragraphStyle.tabStops = [NSTextTab(textAlignment: .left, location: indentation, options: nonOptions)]
paragraphStyle.defaultTabInterval = indentation
paragraphStyle.lineSpacing = lineSpacing
paragraphStyle.paragraphSpacing = paragraphSpacing
paragraphStyle.headIndent = indentation
let bulletList = NSMutableAttributedString()
for string in stringList {
let formattedString = "\(bullet)\t\(string)\n"
let attributedString = NSMutableAttributedString(string: formattedString)
attributedString.addAttributes(
[NSAttributedStringKey.paragraphStyle : paragraphStyle],
range: NSMakeRange(0, attributedString.length))
attributedString.addAttributes(
textAttributes,
range: NSMakeRange(0, attributedString.length))
let string:NSString = NSString(string: formattedString)
let rangeForBullet:NSRange = string.range(of: bullet)
attributedString.addAttributes(bulletAttributes, range: rangeForBullet)
bulletList.append(attributedString)
}
return bulletList
}
What I am looking for is a way to pass in a boolean to state if the bullet string requires either bold or italic text and if so what the elements of the intital string are that need this treatment.
The bulletPoints function sits in an extension file and works as expected.
Using a model to link the bold/italic to the strings in question, as Neil suggests, helps you in this case. Here's a version which links font traits to the strings for each bullet, then uses those when building up the string.
I've refactored your bulletPoints function as well, to remove the use of ranges and simplify it a little. It could stay in an extension (I assume you have it on UILabel?) but there's no reason for it to, since it returns the string anyway. I've written it as a function which could be used in any class
class ViewController: UIViewController {
#IBOutlet var label: UILabel!
override func viewWillAppear(_ animated: Bool) {
let bulletStrings = [BulletString(string: "String 1", traits: []),
BulletString(string: "String 2", traits: [.traitBold]),
BulletString(string: "String 3", traits: [.traitItalic]),
BulletString(string: "String 4", traits: [.traitBold, .traitItalic])]
label.attributedText = bulletPoints(stringList: bulletStrings, font: UIFont.systemFont(ofSize: 15.0), bullet: "•", lineSpacing: 4, paragraphSpacing: 4, textColor: UIColor.darkGray, bulletColor: UIColor.darkGray)
}
func bulletPoints(stringList: [BulletString],
font: UIFont,
bullet: String = "\u{2022}",
indentation: CGFloat = 20,
lineSpacing: CGFloat = 2,
paragraphSpacing: CGFloat = 12,
textColor: UIColor = .gray,
bulletColor: UIColor = .red) -> NSAttributedString {
let bulletList = NSMutableAttributedString()
for bulletString in stringList {
let attributedString = NSMutableAttributedString(string: "")
let bulletAttributes: [NSAttributedStringKey: Any] = [
.foregroundColor: bulletColor,
.font: font]
attributedString.append(NSAttributedString(string: bullet, attributes: bulletAttributes))
let textAttributes: [NSAttributedStringKey: Any] = [
.font: font.withTraits(traits: bulletString.traits),
.foregroundColor: textColor,
.paragraphStyle : paragraphStyle(indentation: indentation, lineSpacing: lineSpacing, paragraphSpacing: paragraphSpacing)
]
attributedString.append(NSAttributedString(string:"\t\(bulletString.string)\n", attributes: textAttributes))
bulletList.append(attributedString)
}
return bulletList
}
private func paragraphStyle(indentation: CGFloat, lineSpacing: CGFloat, paragraphSpacing: CGFloat) -> NSParagraphStyle {
let style = NSMutableParagraphStyle()
let nonOptions = [NSTextTab.OptionKey: Any]()
style.tabStops = [NSTextTab(textAlignment: .left, location: indentation, options: nonOptions)]
style.defaultTabInterval = indentation
style.lineSpacing = lineSpacing
style.paragraphSpacing = paragraphSpacing
style.headIndent = indentation
return style
}
}
struct BulletString {
let string: String
let traits: UIFontDescriptorSymbolicTraits
}
extension UIFont {
func withTraits(traits:UIFontDescriptorSymbolicTraits...) -> UIFont {
let descriptor = self.fontDescriptor
.withSymbolicTraits(UIFontDescriptorSymbolicTraits(traits))!
return UIFont(descriptor: descriptor, size: 0)
}
}
If you wanted to have the bullets match the style of their strings, i.e. be bolded or italicised, you could just add the attributes in a single pass for each bullet
You can achieve it using multiple fonts and text ranges. If you know the ranges of the text on which you want to apply multiple styles, you can just use fonts. Check the below example.
let fullString = "Bold normal italic"
let attrString = NSMutableAttributedString(string: fullString, attributes: [.font: UIFont.systemFont(ofSize: 18.0)])
let range1 = (fullString as NSString).range(of: "Bold")
let range2 = (fullString as NSString).range(of: "italic")
attrString.addAttributes([.font: UIFont.boldSystemFont(ofSize: 20.0)], range: range1)
attrString.addAttributes([.font: UIFont.boldSystemFont(ofSize: 20.0).italics()], range: range2)
label.attributedText = attrString
Whereas I use simple extension for UIFont.
extension UIFont {
func withTraits(_ traits: UIFontDescriptorSymbolicTraits) -> UIFont {
if let fd = fontDescriptor.withSymbolicTraits(traits) {
return UIFont(descriptor: fd, size: pointSize)
}
return self
}
func italics() -> UIFont {
return withTraits(.traitItalic)
}
}
So basically, what you need to know is, which text should be marked as italic, bold and normal. Afterwards just calculate the ranges for those texts in your original text using NSString.range(of: ) and update the attributes appropriately.
Note: You can also calculate the range using start and endIndex. For reference check this SO answer.
One of the possible ways to make it work with the function mentioned in the question - to modify stringList parameter.
First of all let's define model class BulletString:
class BulletString {
var text: String
var attributes: [NSAttributedStringKey : Any]?
init(string: String) {
text = string
}
}
Now your bullet stringList in you function should be [BulletString] type. Define two bulletStrings and pass them to your function. Here is a working solution with your function:
let bulletString1 = BulletString.init(string: "string1")
bulletString1.attributes = [NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 18.0)]
let bulletString2 = BulletString.init(string: "string2")
let bullets = [bulletString1, bulletString2]
label.attributedText = bulletPoints(stringList: bullets, font: UIFont.systemFont(ofSize: 17), bullet: "•", lineSpacing: 4, paragraphSpacing: 4, textColor: UIColor.darkGray, bulletColor: UIColor.darkGray)
label.textColor = .black
func bulletPoints(stringList: [BulletString], font: UIFont,bullet: String = "\u{2022}",indentation: CGFloat = 20,lineSpacing: CGFloat = 2,paragraphSpacing: CGFloat = 12,textColor: UIColor = .gray,bulletColor: UIColor = .red) -> NSAttributedString{
let textAttributes: [NSAttributedStringKey: Any] = [NSAttributedStringKey.font: font, NSAttributedStringKey.foregroundColor: textColor]
let bulletAttributes: [NSAttributedStringKey: Any] = [NSAttributedStringKey.font: font, NSAttributedStringKey.foregroundColor: bulletColor]
let paragraphStyle = NSMutableParagraphStyle()
let nonOptions = [NSTextTab.OptionKey: Any]()
paragraphStyle.tabStops = [NSTextTab(textAlignment: .left, location: indentation, options: nonOptions)]
paragraphStyle.defaultTabInterval = indentation
paragraphStyle.lineSpacing = lineSpacing
paragraphStyle.paragraphSpacing = paragraphSpacing
paragraphStyle.headIndent = indentation
let bulletList = NSMutableAttributedString()
for bulletString in stringList {
let formattedString = "\(bullet)\t\(bulletString.text)\n"
let attributedString = NSMutableAttributedString(string: formattedString)
attributedString.addAttributes(
[NSAttributedStringKey.paragraphStyle : paragraphStyle],
range: NSMakeRange(0, attributedString.length))
attributedString.addAttributes(
textAttributes,
range: NSMakeRange(0, attributedString.length))
// Here your custom attributes you provided in BulletString
if let attr = bulletString.attributes {
attributedString.addAttributes(attr, range: NSMakeRange(0, attributedString.length))
}
let string:NSString = NSString(string: formattedString)
let rangeForBullet:NSRange = string.range(of: bullet)
attributedString.addAttributes(bulletAttributes, range: rangeForBullet)
bulletList.append(attributedString)
}
return bulletList
}
Results

Crash replacing characters on NSAttributedString

Any idea why this crashes:
extension NSAttributedString {
func replaceCharacters(inRange: NSRange, withString: String) -> NSAttributedString {
let mutableString = mutableCopy() as! NSMutableAttributedString
mutableString.replaceCharacters(in: inRange, with: withString)
return mutableString
}
}
let label = UILabel()
label.attributedText = NSAttributedString(string: "abcdef")
let string = label.attributedText?.replaceCharacters(inRange: NSRange(location: 1, length: 1), withString: "-")
But this doesn't?
let label = UILabel()
label.attributedText = NSAttributedString(string: "abcdef")
let mutableString = label.attributedText?.mutableCopy() as! NSMutableAttributedString
mutableString.replaceCharacters(in: NSRange(location: 1, length: 1), with: "-")
let string: NSAttributedString = mutableString
PS: all I did on the second gist was copy the code from inside the replaceCharacters(inRange:withString:) from the first gist.
Try this:
extension String {
func replaceCharacters(withString: String) -> NSAttributedString {
var range = (self as NSString).range(of: withString)
let attributedString = NSMutableAttributedString(string:self)
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.black, range: range)
if let font = UIFont(name: "Helvetica Bold", size: 14) {
attributedString.addAttribute(NSFontAttributeName, value: font, range: range)
}
return attributedString
}
}
let label = UILabel()
label.attributedText = "pqr abcdefg xyz".replaceCharacters("abc")
Note: Please String addAttribute as per your requirement
Try this, This will help you
Swift 3 :
let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
let attrString = NSMutableAttributedString(string: "abcdef")
attrString.mutableString.replaceCharacters(in: NSRange(location: 1, length: 1), with: "-")
label.attributedText = NSAttributedString(string: attrString.string)
print(label.attributedText!)
}

Color up text in textview within a specific range [duplicate]

The issue I am having is that I want to be able to change the textColor of certain text in a TextView. I am using a concatenated string, and just want the strings I am appending into the TextView's text. It appears that what I want to use is NSMutableAttributedString, but I am not finding any resources of how to use this in Swift. What I have so far is something like this:
let string = "A \(stringOne) with \(stringTwo)"
var attributedString = NSMutableAttributedString(string: string)
textView.attributedText = attributedString
From here I know I need to find the range of words that need to have their textColor changed and then add them to the attributed string. What I need to know is how to find the correct strings from the attributedString, and then change their textColor.
Since I have too low of a rating I can't answer my own question, but here is the answer I found
I found my own answer by translating from translating some code from
Change attributes of substrings in a NSAttributedString
Here is the example of implementation in Swift:
let string = "A \(stringOne) and \(stringTwo)"
var attributedString = NSMutableAttributedString(string:string)
let stringOneRegex = NSRegularExpression(pattern: nameString, options: nil, error: nil)
let stringOneMatches = stringOneRegex.matchesInString(longString, options: nil, range: NSMakeRange(0, attributedString.length))
for stringOneMatch in stringOneMatches {
let wordRange = stringOneMatch.rangeAtIndex(0)
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.nameColor(), range: wordRange)
}
textView.attributedText = attributedString
Since I am wanting to change the textColor of multiple Strings I will make a helper function to handle this, but this works for changing the textColor.
let mainString = "Hello World"
let stringToColor = "World"
SWIFT 5
let range = (mainString as NSString).range(of: stringToColor)
let mutableAttributedString = NSMutableAttributedString.init(string: mainString)
mutableAttributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.red, range: range)
textField = UITextField.init(frame: CGRect(x:10, y:20, width:100, height: 100))
textField.attributedText = mutableAttributedString
SWIFT 4.2
let range = (mainString as NSString).range(of: stringToColor)
let mutableAttributedString = NSMutableAttributedString.init(string: mainString)
mutableAttributedString.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.red, range: range)
textField = UITextField.init(frame: CGRect(x:10, y:20, width:100, height: 100))
textField.attributedText = mutableAttributedString
I see you have answered the question somewhat, but to provide a slightly more concise way without using regex to answer to the title question:
To change the colour of a length of text you need to know the start and end index of the coloured-to-be characters in the string e.g.
var main_string = "Hello World"
var string_to_color = "World"
var range = (main_string as NSString).rangeOfString(string_to_color)
Then you convert to attributed string and use 'add attribute' with NSForegroundColorAttributeName:
var attributedString = NSMutableAttributedString(string:main_string)
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor() , range: range)
A list of further standard attributes you can set can be found in Apple's documentation
Swift 2.1 Update:
let text = "We tried to make this app as most intuitive as possible for you. If you have any questions don't hesitate to ask us. For a detailed manual just click here."
let linkTextWithColor = "click here"
let range = (text as NSString).rangeOfString(linkTextWithColor)
let attributedString = NSMutableAttributedString(string:text)
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor() , range: range)
self.helpText.attributedText = attributedString
self.helpText is a UILabel outlet.
Swift 4.2 and Swift 5 colorise parts of the string.
A very easy way to use NSMutableAttributedString while extending the String. This also can be used to colourize more than one word in the whole string.
import UIKit
extension String {
func attributedStringWithColor(_ strings: [String], color: UIColor, characterSpacing: UInt? = nil) -> NSAttributedString {
let attributedString = NSMutableAttributedString(string: self)
for string in strings {
let range = (self as NSString).range(of: string)
attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: color, range: range)
}
guard let characterSpacing = characterSpacing else {return attributedString}
attributedString.addAttribute(NSAttributedString.Key.kern, value: characterSpacing, range: NSRange(location: 0, length: attributedString.length))
return attributedString
}
}
Now you can use globally at any viewcontroller you want:
let attributedWithTextColor: NSAttributedString = "Doc, welcome back :)".attributedStringWithColor(["Doc", "back"], color: UIColor.black)
myLabel.attributedText = attributedWithTextColor
Answer is already given in previous posts but i have a different way of doing this
Swift 3x :
var myMutableString = NSMutableAttributedString()
myMutableString = NSMutableAttributedString(string: "Your full label textString")
myMutableString.setAttributes([NSFontAttributeName : UIFont(name: "HelveticaNeue-Light", size: CGFloat(17.0))!
, NSForegroundColorAttributeName : UIColor(red: 232 / 255.0, green: 117 / 255.0, blue: 40 / 255.0, alpha: 1.0)], range: NSRange(location:12,length:8)) // What ever range you want to give
yourLabel.attributedText = myMutableString
Hope this helps anybody!
Chris' answer was a great help to me, so I used his approach and turned into a func that I can reuse. This let's me assign a color to a substring while giving the rest of the string another color.
static func createAttributedString(fullString: String, fullStringColor: UIColor, subString: String, subStringColor: UIColor) -> NSMutableAttributedString
{
let range = (fullString as NSString).rangeOfString(subString)
let attributedString = NSMutableAttributedString(string:fullString)
attributedString.addAttribute(NSForegroundColorAttributeName, value: fullStringColor, range: NSRange(location: 0, length: fullString.characters.count))
attributedString.addAttribute(NSForegroundColorAttributeName, value: subStringColor, range: range)
return attributedString
}
Swift 4.1
NSAttributedStringKey.foregroundColor
for example if you want to change font in NavBar:
self.navigationController?.navigationBar.titleTextAttributes = [ NSAttributedStringKey.font: UIFont.systemFont(ofSize: 22), NSAttributedStringKey.foregroundColor: UIColor.white]
You can use this extension
I test it over
swift 4.2
import Foundation
import UIKit
extension NSMutableAttributedString {
convenience init (fullString: String, fullStringColor: UIColor, subString: String, subStringColor: UIColor) {
let rangeOfSubString = (fullString as NSString).range(of: subString)
let rangeOfFullString = NSRange(location: 0, length: fullString.count)//fullString.range(of: fullString)
let attributedString = NSMutableAttributedString(string:fullString)
attributedString.addAttribute(NSAttributedStringKey.foregroundColor, value: fullStringColor, range: rangeOfFullString)
attributedString.addAttribute(NSAttributedStringKey.foregroundColor, value: subStringColor, range: rangeOfSubString)
self.init(attributedString: attributedString)
}
}
Swift 2.2
var myMutableString = NSMutableAttributedString()
myMutableString = NSMutableAttributedString(string: "1234567890", attributes: [NSFontAttributeName:UIFont(name: kDefaultFontName, size: 14.0)!])
myMutableString.addAttribute(NSForegroundColorAttributeName, value: UIColor(red: 0.0/255.0, green: 125.0/255.0, blue: 179.0/255.0, alpha: 1.0), range: NSRange(location:0,length:5))
self.lblPhone.attributedText = myMutableString
Easiest way to do label with different style such as color, font etc. is use property "Attributed" in Attributes Inspector. Just choose part of text and change it like you want
Based on the answers before I created a string extension
extension String {
func highlightWordsIn(highlightedWords: String, attributes: [[NSAttributedStringKey: Any]]) -> NSMutableAttributedString {
let range = (self as NSString).range(of: highlightedWords)
let result = NSMutableAttributedString(string: self)
for attribute in attributes {
result.addAttributes(attribute, range: range)
}
return result
}
}
You can pass the attributes for the text to the method
Call like this
let attributes = [[NSAttributedStringKey.foregroundColor:UIColor.red], [NSAttributedStringKey.font: UIFont.boldSystemFont(ofSize: 17)]]
myLabel.attributedText = "This is a text".highlightWordsIn(highlightedWords: "is a text", attributes: attributes)
Swift 4.1
I have changed from this
In Swift 3
let str = "Welcome "
let welcomeAttribute = [ NSForegroundColorAttributeName: UIColor.blue()]
let welcomeAttrString = NSMutableAttributedString(string: str, attributes: welcomeAttribute)
And this in Swift 4.0
let str = "Welcome "
let welcomeAttribute = [ NSAttributedStringKey.foregroundColor: UIColor.blue()]
let welcomeAttrString = NSMutableAttributedString(string: str, attributes: welcomeAttribute)
to Swift 4.1
let str = "Welcome "
let welcomeAttribute = [ NSAttributedStringKey(rawValue: NSForegroundColorAttributeName): UIColor.blue()]
let welcomeAttrString = NSMutableAttributedString(string: str, attributes: welcomeAttribute)
Works fine
swift 4.2
let textString = "Hello world"
let range = (textString as NSString).range(of: "world")
let attributedString = NSMutableAttributedString(string: textString)
attributedString.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.red, range: range)
self.textUIlable.attributedText = attributedString
This might be work for you
let main_string = " User not found,Want to review ? Click here"
let string_to_color = "Click here"
let range = (main_string as NSString).range(of: string_to_color)
let attribute = NSMutableAttributedString.init(string: main_string)
attribute.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.blue , range: range)
lblClickHere.attributedText = attribute
With this simple function you can assign the text and highlight the chosen word.
You can also change the UITextView to UILabel, etc.
func highlightBoldWordAtLabel(textViewTotransform: UITextView, completeText: String, wordToBold: String){
textViewToTransform.text = completeText
let range = (completeText as NSString).range(of: wordToBold)
let attribute = NSMutableAttributedString.init(string: completeText)
attribute.addAttribute(NSAttributedString.Key.font, value: UIFont.boldSystemFont(ofSize: 16), range: range)
attribute.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.black , range: range)
textViewToTransform.attributedText = attribute
}
For everyone who are looking for "Applying specific color to multiple words in text", we can do it using NSRegularExpression
func highlight(matchingText: String, in text: String) {
let attributedString = NSMutableAttributedString(string: text)
if let regularExpression = try? NSRegularExpression(pattern: "\(matchingText)", options: .caseInsensitive) {
let matchedResults = regularExpression.matches(in: text, options: [], range: NSRange(location: 0, length: attributedString.length))
for matched in matchedResults {
attributedString.addAttributes([NSAttributedStringKey.backgroundColor : UIColor.yellow], range: matched.range)
}
yourLabel.attributedText = attributedString
}
}
Reference link : https://gist.github.com/aquajach/4d9398b95a748fd37e88
You can use as simple extension
extension String{
func attributedString(subStr: String) -> NSMutableAttributedString{
let range = (self as NSString).range(of: subStr)
let attributedString = NSMutableAttributedString(string:self)
attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.red , range: range)
return attributedString
}
}
myLable.attributedText = fullStr.attributedString(subStr: strToChange)
This extension works well when configuring the text of a label with an already set default color.
public extension String {
func setColor(_ color: UIColor, ofSubstring substring: String) -> NSMutableAttributedString {
let range = (self as NSString).range(of: substring)
let attributedString = NSMutableAttributedString(string: self)
attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: color, range: range)
return attributedString
}
}
For example
let text = "Hello World!"
let attributedText = text.setColor(.blue, ofSubstring: "World")
let myLabel = UILabel()
myLabel.textColor = .white
myLabel.attributedText = attributedText
Super easy way to do this.
let text = "This is a colorful attributed string"
let attributedText =
NSMutableAttributedString.getAttributedString(fromString: text)
attributedText.apply(color: .red, subString: "This")
//Apply yellow color on range
attributedText.apply(color: .yellow, onRange: NSMakeRange(5, 4))
For more detail click here:
https://github.com/iOSTechHub/AttributedString
To change color of the font colour, first select attributed instead of plain like in the image below
You then need to select the text in the attributed field and then select the color button on the right-hand side of the alignments. This will change the color.
You can use this method. I implemented this method in my common utility class to access globally.
func attributedString(with highlightString: String, normalString: String, highlightColor: UIColor) -> NSMutableAttributedString {
let attributes = [NSAttributedString.Key.foregroundColor: highlightColor]
let attributedString = NSMutableAttributedString(string: highlightString, attributes: attributes)
attributedString.append(NSAttributedString(string: normalString))
return attributedString
}
If you are using Swift 3x and UITextView, maybe the NSForegroundColorAttributeName won't work (it didn't work for me no matter what approach I tried).
So, after some digging around I found a solution.
//Get the textView somehow
let textView = UITextView()
//Set the attributed string with links to it
textView.attributedString = attributedString
//Set the tint color. It will apply to the link only
textView.tintColor = UIColor.red
You need to change textview parameters, not parameters of attributed string
textView.linkTextAttributes = [
NSAttributedString.Key.foregroundColor: UIColor.red,
NSAttributedString.Key.underlineColor: UIColor.red,
NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue
]
Please check cocoapod Prestyler:
Prestyler.defineRule("$", UIColor.orange)
label.attributedText = "This $text$ is orange".prestyled()
extension String{
// to make text field mandatory * looks
mutating func markAsMandatoryField()-> NSAttributedString{
let main_string = self
let string_to_color = "*"
let range = (main_string as NSString).range(of: string_to_color)
print("The rang = \(range)")
let attribute = NSMutableAttributedString.init(string: main_string)
attribute.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.rgbColor(red: 255.0, green: 0.0, blue: 23.0) , range: range)
return attribute
}
}
use
EmailLbl.attributedText = EmailLbl.text!.markAsMandatoryField()

Swift Attributed Title Syntax

I'm trying to do something like this:
let introText = "This is sample "
let facebookText = "Text"
loginButton.setTitle("\(introText)\(facebookText)", forState: .Normal)
loginButton.addAttribute(NSFontAttributeName, value: UIFont(name: "Arial", size: 15.5)!, range: NSMakeRange(0, introText.characters.count))
loginButton.addAttribute(NSFontAttributeName, value: UIFont(name: "Arial-Bold", size: 15.5)!, range: NSMakeRange(introText.characters.count, facebookText.characters.count))
loginButton.addAttribute(NSForegroundColorAttributeName, value: UIColor.whiteColor(), range: NSMakeRange(0, introText.characters.count + facebookText.characters.count))
in this form:
loginButton.setAttributedTitle(NSMutableAttributedString(
string: "\(introText)\(facebookText)",
attributes: [
// attributes go here
NSForegroundColorAttributeName: UIColor.colorFromCode(0x151515),
]), forState: UIControlState.Normal)
Is it possible for me to do this? I'm having trouble figuring out how to include the range on included attributes.
EDIT
Sorry if it wasn't obvious, but what my code does is it creates an attributed string that reads "This is sample Text" with the word Text bolded as shown. I'm trying to rewrite this code to be in the form of the second syntax I'm showing, if it's even possible.
Thanks!
If you are looking for an attributed text with bolded part, this will do it for you.
extension String {
func getPartOfStringBold(boldPart:String)-> NSAttributedString{
return getPartOfStringBold(boldPart, font: UIFont(name: "Taz-Bold", size: 13)!)
}
//Make your string bold
func getPartOfStringBold(boldPart:String, font:UIFont)-> NSAttributedString{
let attributtedString = NSMutableAttributedString(string: self)
let attrs = [NSFontAttributeName:font]
let rangePart: NSRange = (attributtedString.string as NSString).rangeOfString(boldPart)
attributtedString.addAttributes(attrs, range: rangePart)
return attributtedString
}
//Make your string Italic
func getPartOfStringItalic(italicPart:String)-> NSAttributedString{
let attributtedString = NSMutableAttributedString(string: self)
if let font = UIFont(name: "Taz-LightItalic", size: 13)
{
let attrs = [NSFontAttributeName:font, NSForegroundColorAttributeName:UIColor.blackColor()]
let rangePart: NSRange = (attributtedString.string as NSString).rangeOfString(italicPart)
attributtedString.addAttributes(attrs, range: rangePart)
}
return attributtedString
}
}
as far as I have understood your problem, you want to make a portion of test as bold if yes then here is an extension which I am using for this purpose
import UIKit
import Foundation
extension String
{
static func makeTextBold(preBoldText:String, boldText:String, postBoldText:String, fontSzie:CGFloat) -> NSAttributedString {
let boldAttrs = [NSFontAttributeName : UIFont(name: "HelveticaNeue-Bold", size: fontSzie) as? AnyObject]
let attributedString = NSMutableAttributedString(string:boldText, attributes:boldAttrs as? [String:AnyObject])
let lightAttr = [NSFontAttributeName : UIFont(name: "HelveticaNeue-Light", size: fontSzie) as? AnyObject]
let finalAttributedText = NSMutableAttributedString(string:preBoldText, attributes:lightAttr as? [String:AnyObject])
let postText = NSMutableAttributedString(string:postBoldText, attributes:lightAttr as? [String:AnyObject])
finalAttributedText.appendAttributedString(attributedString)
finalAttributedText.appendAttributedString(postText)
// print(finalAttributedText)
return finalAttributedText
}
}
So basically what this function is doing is that you pass three parameters for text and one for fot size and it will return an attributed string.
Here is an example usage for your case
myLabel.attributedText = String.makeTextBold("This is sample", boldText: "Text", postBoldText: "", fontSzie: 21)
the output would be
This is sample Text
I hope this answer the question :-)

Making text bold using attributed string in swift

I have a string like this
var str = "#text1 this is good #text1"
Now replace text1 with another string, say t 1. I am able to replace the text, but i am not able to bold it. I want to bold the new string t 1, so that the final output will be:
#t 1 this is good #t 1
How can I do it?
All the examples I am seeing are in Objective-C, but I want to do it in Swift.
Usage:
let label = UILabel()
label.attributedText =
NSMutableAttributedString()
.bold("Address: ")
.normal(" Kathmandu, Nepal\n\n")
.orangeHighlight(" Email: ")
.blackHighlight(" prajeet.shrestha#gmail.com ")
.bold("\n\nCopyright: ")
.underlined(" All rights reserved. 2020.")
Result:
Here is a neat way to make a combination of bold and normal texts in a single label plus some other bonus methods.
Extension: Swift 5.*
extension NSMutableAttributedString {
var fontSize:CGFloat { return 14 }
var boldFont:UIFont { return UIFont(name: "AvenirNext-Bold", size: fontSize) ?? UIFont.boldSystemFont(ofSize: fontSize) }
var normalFont:UIFont { return UIFont(name: "AvenirNext-Regular", size: fontSize) ?? UIFont.systemFont(ofSize: fontSize)}
func bold(_ value:String) -> NSMutableAttributedString {
let attributes:[NSAttributedString.Key : Any] = [
.font : boldFont
]
self.append(NSAttributedString(string: value, attributes:attributes))
return self
}
func normal(_ value:String) -> NSMutableAttributedString {
let attributes:[NSAttributedString.Key : Any] = [
.font : normalFont,
]
self.append(NSAttributedString(string: value, attributes:attributes))
return self
}
/* Other styling methods */
func orangeHighlight(_ value:String) -> NSMutableAttributedString {
let attributes:[NSAttributedString.Key : Any] = [
.font : normalFont,
.foregroundColor : UIColor.white,
.backgroundColor : UIColor.orange
]
self.append(NSAttributedString(string: value, attributes:attributes))
return self
}
func blackHighlight(_ value:String) -> NSMutableAttributedString {
let attributes:[NSAttributedString.Key : Any] = [
.font : normalFont,
.foregroundColor : UIColor.white,
.backgroundColor : UIColor.black
]
self.append(NSAttributedString(string: value, attributes:attributes))
return self
}
func underlined(_ value:String) -> NSMutableAttributedString {
let attributes:[NSAttributedString.Key : Any] = [
.font : normalFont,
.underlineStyle : NSUnderlineStyle.single.rawValue
]
self.append(NSAttributedString(string: value, attributes:attributes))
return self
}
}
Note: If compiler is missing UIFont/UIColor, replace them with NSFont/NSColor.
var normalText = "Hi am normal"
var boldText = "And I am BOLD!"
var attributedString = NSMutableAttributedString(string:normalText)
var attrs = [NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 15)]
var boldString = NSMutableAttributedString(string: boldText, attributes:attrs)
attributedString.append(boldString)
When you want to assign it to a label:
yourLabel.attributedText = attributedString
edit/update: Xcode 13.1 • Swift 5.5.1
If you know HTML and CSS you can use it to easily control the font style, color and size of your attributed string as follow:
DiscussionThe HTML importer should not be called from a background thread (that is, the options dictionary includes documentType with a value of html). It will try to synchronize with the main thread, fail, and time out. Calling it from the main thread works (but can still time out if the HTML contains references to external resources, which should be avoided at all costs). The HTML import mechanism is meant for implementing something like markdown (that is, text styles, colors, and so on), not for general HTML import.
extension StringProtocol {
var html2AttStr: NSAttributedString? {
try? NSAttributedString(data: Data(utf8), options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
}
}
"<style type=\"text/css\">#red{color:#F00}#green{color:#0F0}#blue{color: #00F; font-weight: Bold; font-size: 32}</style><span id=\"red\" >Red,</span><span id=\"green\" > Green </span><span id=\"blue\">and Blue</span>".html2AttStr
If you're working with localised strings, you might not be able to rely on the bold string always being at the end of the sentence. If this is the case then the following works well:
e.g. Query "blah" does not match any items
/* Create the search query part of the text, e.g. "blah".
The variable 'text' is just the value entered by the user. */
let searchQuery = "\"\(text)\""
/* Put the search text into the message */
let message = "Query \(searchQuery). does not match any items"
/* Find the position of the search string. Cast to NSString as we want
range to be of type NSRange, not Swift's Range<Index> */
let range = (message as NSString).rangeOfString(searchQuery)
/* Make the text at the given range bold. Rather than hard-coding a text size,
Use the text size configured in Interface Builder. */
let attributedString = NSMutableAttributedString(string: message)
attributedString.addAttribute(NSFontAttributeName, value: UIFont.boldSystemFontOfSize(label.font.pointSize), range: range)
/* Put the text in a label */
label.attributedText = attributedString
I extended David West's great answer so that you can input a string and tell it all the substrings you would like to embolden:
func addBoldText(fullString: NSString, boldPartsOfString: Array<NSString>, font: UIFont!, boldFont: UIFont!) -> NSAttributedString {
let nonBoldFontAttribute = [NSFontAttributeName:font!]
let boldFontAttribute = [NSFontAttributeName:boldFont!]
let boldString = NSMutableAttributedString(string: fullString as String, attributes:nonBoldFontAttribute)
for i in 0 ..< boldPartsOfString.count {
boldString.addAttributes(boldFontAttribute, range: fullString.rangeOfString(boldPartsOfString[i] as String))
}
return boldString
}
And then call it like this:
let normalFont = UIFont(name: "Dosis-Medium", size: 18)
let boldSearchFont = UIFont(name: "Dosis-Bold", size: 18)
self.UILabel.attributedText = addBoldText("Check again in 30 days to find more friends", boldPartsOfString: ["Check", "30 days", "find", "friends"], font: normalFont!, boldFont: boldSearchFont!)
This will embolden all the substrings you want bolded in your given string
This is the best way that I have come up with. Add a function you can call from anywhere and add it to a file without a class like Constants.swift and then you can embolden words within any string, on numerous occasions by calling just ONE LINE of code:
To go in a constants.swift file:
import Foundation
import UIKit
func addBoldText(fullString: NSString, boldPartOfString: NSString, font: UIFont!, boldFont: UIFont!) -> NSAttributedString {
let nonBoldFontAttribute = [NSFontAttributeName:font!]
let boldFontAttribute = [NSFontAttributeName:boldFont!]
let boldString = NSMutableAttributedString(string: fullString as String, attributes:nonBoldFontAttribute)
boldString.addAttributes(boldFontAttribute, range: fullString.rangeOfString(boldPartOfString as String))
return boldString
}
Then you can just call this one line of code for any UILabel:
self.UILabel.attributedText = addBoldText("Check again in 30 DAYS to find more friends", boldPartOfString: "30 DAYS", font: normalFont!, boldFont: boldSearchFont!)
//Mark: Albeit that you've had to define these somewhere:
let normalFont = UIFont(name: "INSERT FONT NAME", size: 15)
let boldFont = UIFont(name: "INSERT BOLD FONT", size: 15)
Building on Jeremy Bader and David West's excellent answers, a Swift 3 extension:
extension String {
func withBoldText(boldPartsOfString: Array<NSString>, font: UIFont!, boldFont: UIFont!) -> NSAttributedString {
let nonBoldFontAttribute = [NSFontAttributeName:font!]
let boldFontAttribute = [NSFontAttributeName:boldFont!]
let boldString = NSMutableAttributedString(string: self as String, attributes:nonBoldFontAttribute)
for i in 0 ..< boldPartsOfString.count {
boldString.addAttributes(boldFontAttribute, range: (self as NSString).range(of: boldPartsOfString[i] as String))
}
return boldString
}
}
Usage:
let label = UILabel()
let font = UIFont(name: "AvenirNext-Italic", size: 24)!
let boldFont = UIFont(name: "AvenirNext-BoldItalic", size: 24)!
label.attributedText = "Make sure your face is\nbrightly and evenly lit".withBoldText(
boldPartsOfString: ["brightly", "evenly"], font: font, boldFont: boldFont)
Swift 4 and higher
For Swift 4 and higher that is a good way:
let attributsBold = [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16, weight: .bold)]
let attributsNormal = [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16, weight: .regular)]
var attributedString = NSMutableAttributedString(string: "Hi ", attributes:attributsNormal)
let boldStringPart = NSMutableAttributedString(string: "John", attributes:attributsBold)
attributedString.append(boldStringPart)
yourLabel.attributedText = attributedString
In the Label the Text looks like: "Hi John"
usage....
let attrString = NSMutableAttributedString()
.appendWith(weight: .semibold, "almost bold")
.appendWith(color: .white, weight: .bold, " white and bold")
.appendWith(color: .black, ofSize: 18.0, " big black")
two cents...
extension NSMutableAttributedString {
#discardableResult func appendWith(color: UIColor = UIColor.darkText, weight: UIFont.Weight = .regular, ofSize: CGFloat = 12.0, _ text: String) -> NSMutableAttributedString{
let attrText = NSAttributedString.makeWith(color: color, weight: weight, ofSize:ofSize, text)
self.append(attrText)
return self
}
}
extension NSAttributedString {
public static func makeWith(color: UIColor = UIColor.darkText, weight: UIFont.Weight = .regular, ofSize: CGFloat = 12.0, _ text: String) -> NSMutableAttributedString {
let attrs = [NSAttributedStringKey.font: UIFont.systemFont(ofSize: ofSize, weight: weight), NSAttributedStringKey.foregroundColor: color]
return NSMutableAttributedString(string: text, attributes:attrs)
}
}
Accepting as valid the response of Prajeet Shrestha in this thread, I would like to extend his solution using the Label if it is known and the traits of the font.
Swift 4
extension NSMutableAttributedString {
#discardableResult func normal(_ text: String) -> NSMutableAttributedString {
let normal = NSAttributedString(string: text)
append(normal)
return self
}
#discardableResult func bold(_ text: String, withLabel label: UILabel) -> NSMutableAttributedString {
//generate the bold font
var font: UIFont = UIFont(name: label.font.fontName , size: label.font.pointSize)!
font = UIFont(descriptor: font.fontDescriptor.withSymbolicTraits(.traitBold) ?? font.fontDescriptor, size: font.pointSize)
//generate attributes
let attrs: [NSAttributedStringKey: Any] = [NSAttributedStringKey.font: font]
let boldString = NSMutableAttributedString(string:text, attributes: attrs)
//append the attributed text
append(boldString)
return self
}
}
Super easy way to do this.
let text = "This string is having multiple font"
let attributedText =
NSMutableAttributedString.getAttributedString(fromString: text)
attributedText.apply(font: UIFont.boldSystemFont(ofSize: 24), subString:
"This")
attributedText.apply(font: UIFont.boldSystemFont(ofSize: 24), onRange:
NSMakeRange(5, 6))
For more detail click here:
https://github.com/iOSTechHub/AttributedString
For -> Search Television by size
1-way using NString and its Range
let query = "Television"
let headerTitle = "size"
let message = "Search \(query) by \(headerTitle)"
let range = (message as NSString).range(of: query)
let attributedString = NSMutableAttributedString(string: message)
attributedString.addAttribute(NSAttributedString.Key.font, value: UIFont.boldSystemFont(ofSize: label1.font.pointSize), range: range)
label1.attributedText = attributedString
another without using NString and its Range
let query = "Television"
let headerTitle = "size"
let (searchText, byText) = ("Search ", " by \(headerTitle)")
let attributedString = NSMutableAttributedString(string: searchText)
let byTextAttributedString = NSMutableAttributedString(string: byText)
let attrs = [NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: label1.font.pointSize)]
let boldString = NSMutableAttributedString(string: query, attributes:attrs)
attributedString.append(boldString)
attributedString.append(byTextAttributedString)
label1.attributedText = attributedString
swift5
This could be useful
class func createAttributedStringFrom (string1 : String ,strin2 : String, attributes1 : Dictionary<String, NSObject>, attributes2 : Dictionary<String, NSObject>) -> NSAttributedString{
let fullStringNormal = (string1 + strin2) as NSString
let attributedFullString = NSMutableAttributedString(string: fullStringNormal as String)
attributedFullString.addAttributes(attributes1, range: fullStringNormal.rangeOfString(string1))
attributedFullString.addAttributes(attributes2, range: fullStringNormal.rangeOfString(strin2))
return attributedFullString
}
Swift 3.0
Convert html to string and font change as per your requirement.
do {
let str = try NSAttributedString(data: ("I'm a normal text and <b>this is my bold part . </b>And I'm again in the normal text".data(using: String.Encoding.unicode, allowLossyConversion: true)!), options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil)
myLabel.attributedText = str
myLabel.font = MONTSERRAT_BOLD(23)
myLabel.textAlignment = NSTextAlignment.left
} catch {
print(error)
}
func MONTSERRAT_BOLD(_ size: CGFloat) -> UIFont
{
return UIFont(name: "MONTSERRAT-BOLD", size: size)!
}
Swift 5.1
use NSAttributedString.Key instead of NSAttributedStringKey
let test1Attributes:[NSAttributedString.Key: Any] = [.font : UIFont(name: "CircularStd-Book", size: 14)!]
let test2Attributes:[NSAttributedString.Key: Any] = [.font : UIFont(name: "CircularStd-Bold", size: 16)!]
let test1 = NSAttributedString(string: "\(greeting!) ", attributes:test1Attributes)
let test2 = NSAttributedString(string: firstName!, attributes:test2Attributes)
let text = NSMutableAttributedString()
text.append(test1)
text.append(test2)
return text
for making mixed-type strings (Attributed String ) It is better to use Xcode's interface builder if the text is static.
it is very easy and convenient.
Just use code something like this:
let font = UIFont(name: "Your-Font-Name", size: 10.0)!
let attributedText = NSMutableAttributedString(attributedString: noteLabel.attributedText!)
let boldedRange = NSRange(attributedText.string.range(of: "Note:")!, in: attributedText.string)
attributedText.addAttributes([NSAttributedString.Key.font : font], range: boldedRange)
noteLabel.attributedText = attributedText
two liner in swift 4:
button.setAttributedTitle(.init(string: "My text", attributes: [.font: UIFont.systemFont(ofSize: 20, weight: .bold)]), for: .selected)
button.setAttributedTitle(.init(string: "My text", attributes: [.font: UIFont.systemFont(ofSize: 20, weight: .regular)]), for: .normal)
With recent versions (iOS 15+) you can use AttributedString to create Markdown strings :
let rawMarkdown = "This is **bold**"
let content;
do {
content = try AttributedString(markdown: rawMarkdown)
} catch {
content = AttributedString(rawMarkdown)
}
and display them with Swift UI's Text:
Text(content)
Improving upon Prajeet Shrestha answer : -
You can make a generic extension for NSMutableAttributedString which involves less code. In this case I have chosen to use system font but you could adapt it so you can input the font name as a parameter.
extension NSMutableAttributedString {
func systemFontWith(text: String, size: CGFloat, weight: CGFloat) -> NSMutableAttributedString {
let attributes: [String: AnyObject] = [NSFontAttributeName: UIFont.systemFont(ofSize: size, weight: weight)]
let string = NSMutableAttributedString(string: text, attributes: attributes)
self.append(string)
return self
}
}
You can do this using simple custom method written below.
You have give whole string in first parameter and text to be bold in the second parameter. Hope this will help.
func getAttributedBoldString(str : String, boldTxt : String) -> NSMutableAttributedString {
let attrStr = NSMutableAttributedString.init(string: str)
let boldedRange = NSRange(str.range(of: boldTxt)!, in: str)
attrStr.addAttributes([NSAttributedString.Key.font : UIFont.systemFont(ofSize: 17, weight: .bold)], range: boldedRange)
return attrStr
}
usage:
initalString = I am a Boy
label.attributedText = getAttributedBoldString(str : initalString, boldTxt : "Boy")
resultant string = I am a Boy

Resources