Multiline attributed string with strikethrough - ios

I have a label with:
label.numberOfLines = 0
And I'm trying to make text of this label strikethrough with:
let index: NSMutableAttributedString = NSMutableAttributedString(string: label.text!)
index.addAttributes([NSStrikethroughStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue, NSStrikethroughColorAttributeName: UIColor.red], range: NSMakeRange(0, index.length))
label.textColor = UIColor.red
label.attributedText = index
Is it true that attributed string is not working with multilines or with labels with numberOfLines set to 0? And if so, how to make multiline text strikethrough?

Works fine with multiline if you add NSBaselineOffsetAttributeName before:
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: (object?.title)!)
attributeString.addAttribute(NSBaselineOffsetAttributeName, value: 0, range: NSMakeRange(0, attributeString.length))
attributeString.addAttribute(NSStrikethroughStyleAttributeName, value: 2, range: NSMakeRange(0, attributeString.length))

Your code should be like,
let index: NSMutableAttributedString = NSMutableAttributedString(string: lbl.text!)
index.addAttributes([NSStrikethroughStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue, NSStrikethroughColorAttributeName: UIColor.red], range: NSMakeRange(0, index.length))
lbl.textColor = UIColor.red
lbl.attributedText = index
because index is your mutable string! not title!
And you can not use strike through with multi line label.
If you want strike through effect in multiple lines then you can use UITextView instead of label!

Write it like,
self.label.numberOfLines = 0
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: self.label.text!)
attributeString.addAttribute(NSStrikethroughStyleAttributeName, value: 1, range: NSMakeRange(0, attributeString.length))
self.label.attributedText = attributeString
Working at my end.

I came up with two solutions. They are based on #SivajeeBattina answer.
First one is to strike out text with help of http://adamvarga.com/strike/.
private func returnStrikedOutTextFromString(_ str: String) -> String {
var newString = ""
let normal = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя "
let strikethrough = "А̶Б̶В̶Г̶Д̶Е̶Ё̶Ж̶З̶И̶Й̶К̶Л̶М̶Н̶О̶П̶Р̶С̶Т̶У̶Ф̶Х̶Ц̶Ч̶Ш̶Щ̶Ъ̶Ы̶Ь̶Э̶Ю̶Я̶а̶б̶в̶г̶д̶е̶ё̶ж̶з̶и̶й̶к̶л̶м̶н̶о̶п̶р̶с̶т̶у̶ф̶х̶ц̶ч̶ш̶щ̶ъ̶ы̶ь̶э̶ю̶я̶ ̶̶"
for i in 0..<str.characters.count {
let range: Range<String.Index> =
normal.range(of: str
.substring(to: str.index(str.startIndex, offsetBy: i + 1))
.substring(from: str.index(str.startIndex, offsetBy: i)))!
let index: Int = normal.distance(from: normal.startIndex, to: range.lowerBound)
newString = String(format: "%#%#", newString,
NSLocalizedString(strikethrough
.substring(to: strikethrough.index(strikethrough.startIndex, offsetBy: index + 1))
.substring(from: strikethrough.index(strikethrough.startIndex, offsetBy: index)),
comment: ""))
}
return newString
}
And second one is: https://github.com/GuntisTreulands/UnderLineLabel

Related

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!)
}

Deprecated text style UILabel swift3 [duplicate]

I want to create a UILabel in which the text is like this
How can I do this? When the text is small, the line should also be small.
SWIFT 5 UPDATE CODE
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: "Your Text")
attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: 2, range: NSRange(location: 0, length: attributeString.length))
then:
yourLabel.attributedText = attributeString
To make some part of string to strike then provide range
let somePartStringRange = (yourStringHere as NSString).range(of: "Text")
attributeString.addAttribute(NSStrikethroughStyleAttributeName, value: 2, range: somePartStringRange)
Objective-C
In iOS 6.0 > UILabel supports NSAttributedString
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:#"Your String here"];
[attributeString addAttribute:NSStrikethroughStyleAttributeName
value:#2
range:NSMakeRange(0, [attributeString length])];
Swift
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: "Your String here")
attributeString.addAttribute(NSStrikethroughStyleAttributeName, value: 2, range: NSMakeRange(0, attributeString.length))
Definition :
- (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)aRange
Parameters List:
name : A string specifying the attribute name. Attribute keys can be supplied by another framework or can be custom ones you define. For information about where to find the system-supplied attribute keys, see the overview section in NSAttributedString Class Reference.
value : The attribute value associated with name.
aRange : The range of characters to which the specified attribute/value pair applies.
Then
yourLabel.attributedText = attributeString;
For lesser than iOS 6.0 versions you need 3-rd party component to do this.
One of them is TTTAttributedLabel, another is OHAttributedLabel.
In Swift, using the single strikethrough line style:
let attributedText = NSAttributedString(
string: "Label Text",
attributes: [.strikethroughStyle: NSUnderlineStyle.single.rawValue]
)
label.attributedText = attributedText
Additional strikethrough styles (Remember to use the .rawValue):
.none
.single
.thick
.double
Strikethrough patterns (to be OR-ed with the style):
.patternDot
.patternDash
.patternDashDot
.patternDashDotDot
Specify that the strikethrough should only be applied across words (not spaces):
.byWord
I prefer NSAttributedString rather than NSMutableAttributedString for this simple case:
NSAttributedString * title =
[[NSAttributedString alloc] initWithString:#"$198"
attributes:#{NSStrikethroughStyleAttributeName:#(NSUnderlineStyleSingle)}];
[label setAttributedText:title];
Constants for specifying both the NSUnderlineStyleAttributeName and NSStrikethroughStyleAttributeName attributes of an attributed string:
typedef enum : NSInteger {
NSUnderlineStyleNone = 0x00,
NSUnderlineStyleSingle = 0x01,
NSUnderlineStyleThick = 0x02,
NSUnderlineStyleDouble = 0x09,
NSUnderlinePatternSolid = 0x0000,
NSUnderlinePatternDot = 0x0100,
NSUnderlinePatternDash = 0x0200,
NSUnderlinePatternDashDot = 0x0300,
NSUnderlinePatternDashDotDot = 0x0400,
NSUnderlineByWord = 0x8000
} NSUnderlineStyle;
Strikethrough in Swift 5.0
let attributeString = NSMutableAttributedString(string: "Your Text")
attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle,
value: NSUnderlineStyle.single.rawValue,
range: NSMakeRange(0, attributeString.length))
self.yourLabel.attributedText = attributeString
It worked for me like a charm.
Use it as extension
extension String {
func strikeThrough() -> NSAttributedString {
let attributeString = NSMutableAttributedString(string: self)
attributeString.addAttribute(
NSAttributedString.Key.strikethroughStyle,
value: NSUnderlineStyle.single.rawValue,
range:NSMakeRange(0,attributeString.length))
return attributeString
}
}
Call like this
myLabel.attributedText = "my string".strikeThrough()
UILabel extension for strikethrough Enable/Disable.
extension UILabel {
func strikeThrough(_ isStrikeThrough:Bool) {
if isStrikeThrough {
if let lblText = self.text {
let attributeString = NSMutableAttributedString(string: lblText)
attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: NSMakeRange(0,attributeString.length))
self.attributedText = attributeString
}
} else {
if let attributedStringText = self.attributedText {
let txt = attributedStringText.string
self.attributedText = nil
self.text = txt
return
}
}
}
}
Use it like this :
yourLabel.strikeThrough(btn.isSelected) // true OR false
SWIFT CODE
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: "Your Text")
attributeString.addAttribute(NSStrikethroughStyleAttributeName, value: 2, range: NSMakeRange(0, attributeString.length))
then:
yourLabel.attributedText = attributeString
Thanks to Prince answer ;)
SWIFT 4
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: "Your Text Goes Here")
attributeString.addAttribute(NSAttributedStringKey.strikethroughStyle, value: NSUnderlineStyle.styleSingle.rawValue, range: NSMakeRange(0, attributeString.length))
self.lbl_productPrice.attributedText = attributeString
Other method is to used String Extension
Extension
extension String{
func strikeThrough()->NSAttributedString{
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: self)
attributeString.addAttribute(NSAttributedStringKey.strikethroughStyle, value: NSUnderlineStyle.styleSingle.rawValue, range: NSMakeRange(0, attributeString.length))
return attributeString
}
}
Calling the function : Used it like so
testUILabel.attributedText = "Your Text Goes Here!".strikeThrough()
Credit to #Yahya - update Dec 2017
Credit to #kuzdu - update Aug 2018
Strike out UILabel text in Swift iOS. PLease try this it's working for me
let attributedString = NSMutableAttributedString(string:"12345")
attributedString.addAttribute(NSAttributedStringKey.baselineOffset, value: 0, range: NSMakeRange(0, attributedString.length))
attributedString.addAttribute(NSAttributedStringKey.strikethroughStyle, value: NSNumber(value: NSUnderlineStyle.styleThick.rawValue), range: NSMakeRange(0, attributedString.length))
attributedString.addAttribute(NSAttributedStringKey.strikethroughColor, value: UIColor.gray, range: NSMakeRange(0, attributedString.length))
yourLabel.attributedText = attributedString
You can change your "strikethroughStyle" like styleSingle, styleThick,styleDouble
You can do it in IOS 6 using NSMutableAttributedString.
NSMutableAttributedString *attString=[[NSMutableAttributedString alloc]initWithString:#"$198"];
[attString addAttribute:NSStrikethroughStyleAttributeName value:[NSNumber numberWithInt:2] range:NSMakeRange(0,[attString length])];
yourLabel.attributedText = attString;
Swift 5
extension String {
/// Apply strike font on text
func strikeThrough() -> NSAttributedString {
let attributeString = NSMutableAttributedString(string: self)
attributeString.addAttribute(
NSAttributedString.Key.strikethroughStyle,
value: 1,
range: NSRange(location: 0, length: attributeString.length))
return attributeString
}
}
Example:
someLabel.attributedText = someText.strikeThrough()
For anyone looking on how to do this in a tableview cell (Swift) you have to set the .attributeText like this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TheCell")!
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: message)
attributeString.addAttribute(NSStrikethroughStyleAttributeName, value: 2, range: NSMakeRange(0, attributeString.length))
cell.textLabel?.attributedText = attributeString
return cell
}
If you want to remove the strikethrough do this otherwise it will stick around!:
cell.textLabel?.attributedText = nil
I might be late to the party.
Anyway, I am aware about the NSMutableAttributedString but recently I achieved the same functionality with slightly different approach.
I added the UIView with height = 1.
Matched the leading and trailing constraints of the UIView with the label's leading and trailing constraints
Aligned the UIView at centre of the Label
After following all the above steps my Label, UIView and its constraints were looking like below image.
Swift5 UILabel Extension. Removing strikethrough sometimes doesn't work. Use this code in that case.
extension UILabel {
func strikeThrough(_ isStrikeThrough: Bool = true) {
guard let text = self.text else {
return
}
if isStrikeThrough {
let attributeString = NSMutableAttributedString(string: text)
attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: NSMakeRange(0,attributeString.length))
self.attributedText = attributeString
} else {
let attributeString = NSMutableAttributedString(string: text)
attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: [], range: NSMakeRange(0,attributeString.length))
self.attributedText = attributeString
}
}
}
Use below code
NSString* strPrice = #"£399.95";
NSMutableAttributedString *titleString = [[NSMutableAttributedString alloc] initWithString:strPrice];
[finalString addAttribute: NSStrikethroughStyleAttributeName value:[NSNumber numberWithInteger: NSUnderlineStyleSingle] range: NSMakeRange(0, [titleString length])];
self.lblOldPrice.attributedText = finalString;
Swift 4.2
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: product.price)
attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: NSMakeRange(0, attributeString.length))
lblPrice.attributedText = attributeString
Swift 5 - short version
let attributedText = NSAttributedString(
string: "Label Text",
attributes: [.strikethroughStyle: NSUnderlineStyle.single.rawValue]
)
yourLabel.attributedText = attributedText
Change the text property to attributed and select the text and right click to get the font property. Click on the strikethrough.
On iOS 10.3 has an issue on rendering strikethrough line fixes by Adding a NSBaselineOffsetAttributeName, as explained here, to the attributed string brings back the strikethrough line. Overriding drawText:in: can be slow especially on Collection View or Table View Cells.
One sol - Add view to render a line.
Second sol -
attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: 2, range: NSMakeRange(0, attributeString.length))
attributeString.addAttribute(NSAttributedString.Key.baselineOffset, value: 2, range: NSMakeRange(0, attributeString.length))```
Swift 4 and 5
extension NSAttributedString {
/// Returns a new instance of NSAttributedString with same contents and attributes with strike through added.
/// - Parameter style: value for style you wish to assign to the text.
/// - Returns: a new instance of NSAttributedString with given strike through.
func withStrikeThrough(_ style: Int = 1) -> NSAttributedString {
let attributedString = NSMutableAttributedString(attributedString: self)
attributedString.addAttribute(.strikethroughStyle,
value: style,
range: NSRange(location: 0, length: string.count))
return NSAttributedString(attributedString: attributedString)
}
}
Example
let example = NSAttributedString(string: "440").withStrikeThrough(1)
myLabel.attributedText = example
Results
For those who face issue with multi line text strike
let attributedString = NSMutableAttributedString(string: item.name!)
//necessary if UILabel text is multilines
attributedString.addAttribute(NSBaselineOffsetAttributeName, value: 0, range: NSMakeRange(0, attributedString.length))
attributedString.addAttribute(NSStrikethroughStyleAttributeName, value: NSNumber(value: NSUnderlineStyle.styleSingle.rawValue), range: NSMakeRange(0, attributedString.length))
attributedString.addAttribute(NSStrikethroughColorAttributeName, value: UIColor.darkGray, range: NSMakeRange(0, attributedString.length))
cell.lblName.attributedText = attributedString
Create String extension and add below method
static func makeSlashText(_ text:String) -> NSAttributedString {
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: text)
attributeString.addAttribute(NSStrikethroughStyleAttributeName, value: 2, range: NSMakeRange(0, attributeString.length))
return attributeString
}
then use for your label like this
yourLabel.attributedText = String.makeSlashText("Hello World!")
This is the one you can use in Swift 4 because NSStrikethroughStyleAttributeName has been changed to NSAttributedStringKey.strikethroughStyle
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: "Your Text")
attributeString.addAttribute(NSAttributedStringKey.strikethroughStyle, value: 2, range: NSMakeRange(0, attributeString.length))
self.lbl.attributedText = attributeString

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 change color of text using NSMutableAttributedStrings

I have a UITableView and i would like to display the text of each row using different colors within the same line.
I've tried this code, trying to translate from Obj-C but i cannot have it working
let object = self.fetchedResultsController.objectAtIndexPath(indexPath) as NSManagedObject
var attrString: NSMutableAttributedString = NSMutableAttributedString(string: object.valueForKey("example1")!.description)
attrString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: NSMakeRange(0, attrString.length))
var stringToCell:String = String(format: "%# %#", attrString, object.valueForKey("example2")!.description)
cell.textLabel?.text = stringToCell
The output of all this is
where the number 34 correspond to object.valueForKey("example1")!.description, so the problem is that the number is not red, and the second part (object.valueForKey("example2")!.description) is replaced by {.
If I leave this piece of code regarding NSAttributedString the row text is displayed correctly.
I think the problem might lie in assigning to cell.textLabel?.text instead of cell.textLabel?.attributedText. Perhaps something like this:
let object = self.fetchedResultsController.objectAtIndexPath(indexPath) as NSManagedObject
var attrString: NSMutableAttributedString = NSMutableAttributedString(string: object.valueForKey("example1")!.description)
attrString.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: NSMakeRange(0, attrString.length))
var descString: NSMutableAttributedString = NSMutableAttributedString(string: String(format: " %#", object.valueForKey("example2")!.description))
descString.addAttribute(NSForegroundColorAttributeName, value: UIColor.blackColor(), range: NSMakeRange(0, descString.length))
attrString.appendAttributedString(descString);
cell.textLabel?.attributedText = attrString
Wasn't sure if you wanted the second part of the string to be red or another color so I made it black.
If you can, avoid using NSMutableAttributedString and just pass in the attributes with the constructor:
private func PullToRefreshAttributedStringWithColor(color:UIColor) -> NSAttributedString {
return NSAttributedString(string: "Pull to Refresh", attributes: [
NSForegroundColorAttributeName:color
])
}
Here is a example of attribute text Swift 3
let mainText = "Here is a example of attributedString"
let attributeText = "attributedString"
let range = (mainText as NSString).range(of: attributeText)
let attributedString = NSMutableAttributedString(string:mainText)
attributedString.addAttribute(NSAttributedStringKey.foregroundColor, value: UIColor.red, range: range)
attribute.addAttribute(NSFontAttributeName, value: UIFont.systemFont(ofSize: 14) , range: range)
lblTitle.attributedText = attributedString

How can I create a UILabel with strikethrough text?

I want to create a UILabel in which the text is like this
How can I do this? When the text is small, the line should also be small.
SWIFT 5 UPDATE CODE
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: "Your Text")
attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: 2, range: NSRange(location: 0, length: attributeString.length))
then:
yourLabel.attributedText = attributeString
To make some part of string to strike then provide range
let somePartStringRange = (yourStringHere as NSString).range(of: "Text")
attributeString.addAttribute(NSStrikethroughStyleAttributeName, value: 2, range: somePartStringRange)
Objective-C
In iOS 6.0 > UILabel supports NSAttributedString
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:#"Your String here"];
[attributeString addAttribute:NSStrikethroughStyleAttributeName
value:#2
range:NSMakeRange(0, [attributeString length])];
Swift
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: "Your String here")
attributeString.addAttribute(NSStrikethroughStyleAttributeName, value: 2, range: NSMakeRange(0, attributeString.length))
Definition :
- (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)aRange
Parameters List:
name : A string specifying the attribute name. Attribute keys can be supplied by another framework or can be custom ones you define. For information about where to find the system-supplied attribute keys, see the overview section in NSAttributedString Class Reference.
value : The attribute value associated with name.
aRange : The range of characters to which the specified attribute/value pair applies.
Then
yourLabel.attributedText = attributeString;
For lesser than iOS 6.0 versions you need 3-rd party component to do this.
One of them is TTTAttributedLabel, another is OHAttributedLabel.
In Swift, using the single strikethrough line style:
let attributedText = NSAttributedString(
string: "Label Text",
attributes: [.strikethroughStyle: NSUnderlineStyle.single.rawValue]
)
label.attributedText = attributedText
Additional strikethrough styles (Remember to use the .rawValue):
.none
.single
.thick
.double
Strikethrough patterns (to be OR-ed with the style):
.patternDot
.patternDash
.patternDashDot
.patternDashDotDot
Specify that the strikethrough should only be applied across words (not spaces):
.byWord
I prefer NSAttributedString rather than NSMutableAttributedString for this simple case:
NSAttributedString * title =
[[NSAttributedString alloc] initWithString:#"$198"
attributes:#{NSStrikethroughStyleAttributeName:#(NSUnderlineStyleSingle)}];
[label setAttributedText:title];
Constants for specifying both the NSUnderlineStyleAttributeName and NSStrikethroughStyleAttributeName attributes of an attributed string:
typedef enum : NSInteger {
NSUnderlineStyleNone = 0x00,
NSUnderlineStyleSingle = 0x01,
NSUnderlineStyleThick = 0x02,
NSUnderlineStyleDouble = 0x09,
NSUnderlinePatternSolid = 0x0000,
NSUnderlinePatternDot = 0x0100,
NSUnderlinePatternDash = 0x0200,
NSUnderlinePatternDashDot = 0x0300,
NSUnderlinePatternDashDotDot = 0x0400,
NSUnderlineByWord = 0x8000
} NSUnderlineStyle;
Strikethrough in Swift 5.0
let attributeString = NSMutableAttributedString(string: "Your Text")
attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle,
value: NSUnderlineStyle.single.rawValue,
range: NSMakeRange(0, attributeString.length))
self.yourLabel.attributedText = attributeString
It worked for me like a charm.
Use it as extension
extension String {
func strikeThrough() -> NSAttributedString {
let attributeString = NSMutableAttributedString(string: self)
attributeString.addAttribute(
NSAttributedString.Key.strikethroughStyle,
value: NSUnderlineStyle.single.rawValue,
range:NSMakeRange(0,attributeString.length))
return attributeString
}
}
Call like this
myLabel.attributedText = "my string".strikeThrough()
UILabel extension for strikethrough Enable/Disable.
extension UILabel {
func strikeThrough(_ isStrikeThrough:Bool) {
if isStrikeThrough {
if let lblText = self.text {
let attributeString = NSMutableAttributedString(string: lblText)
attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: NSMakeRange(0,attributeString.length))
self.attributedText = attributeString
}
} else {
if let attributedStringText = self.attributedText {
let txt = attributedStringText.string
self.attributedText = nil
self.text = txt
return
}
}
}
}
Use it like this :
yourLabel.strikeThrough(btn.isSelected) // true OR false
SWIFT CODE
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: "Your Text")
attributeString.addAttribute(NSStrikethroughStyleAttributeName, value: 2, range: NSMakeRange(0, attributeString.length))
then:
yourLabel.attributedText = attributeString
Thanks to Prince answer ;)
SWIFT 4
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: "Your Text Goes Here")
attributeString.addAttribute(NSAttributedStringKey.strikethroughStyle, value: NSUnderlineStyle.styleSingle.rawValue, range: NSMakeRange(0, attributeString.length))
self.lbl_productPrice.attributedText = attributeString
Other method is to used String Extension
Extension
extension String{
func strikeThrough()->NSAttributedString{
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: self)
attributeString.addAttribute(NSAttributedStringKey.strikethroughStyle, value: NSUnderlineStyle.styleSingle.rawValue, range: NSMakeRange(0, attributeString.length))
return attributeString
}
}
Calling the function : Used it like so
testUILabel.attributedText = "Your Text Goes Here!".strikeThrough()
Credit to #Yahya - update Dec 2017
Credit to #kuzdu - update Aug 2018
Strike out UILabel text in Swift iOS. PLease try this it's working for me
let attributedString = NSMutableAttributedString(string:"12345")
attributedString.addAttribute(NSAttributedStringKey.baselineOffset, value: 0, range: NSMakeRange(0, attributedString.length))
attributedString.addAttribute(NSAttributedStringKey.strikethroughStyle, value: NSNumber(value: NSUnderlineStyle.styleThick.rawValue), range: NSMakeRange(0, attributedString.length))
attributedString.addAttribute(NSAttributedStringKey.strikethroughColor, value: UIColor.gray, range: NSMakeRange(0, attributedString.length))
yourLabel.attributedText = attributedString
You can change your "strikethroughStyle" like styleSingle, styleThick,styleDouble
You can do it in IOS 6 using NSMutableAttributedString.
NSMutableAttributedString *attString=[[NSMutableAttributedString alloc]initWithString:#"$198"];
[attString addAttribute:NSStrikethroughStyleAttributeName value:[NSNumber numberWithInt:2] range:NSMakeRange(0,[attString length])];
yourLabel.attributedText = attString;
Swift 5
extension String {
/// Apply strike font on text
func strikeThrough() -> NSAttributedString {
let attributeString = NSMutableAttributedString(string: self)
attributeString.addAttribute(
NSAttributedString.Key.strikethroughStyle,
value: 1,
range: NSRange(location: 0, length: attributeString.length))
return attributeString
}
}
Example:
someLabel.attributedText = someText.strikeThrough()
For anyone looking on how to do this in a tableview cell (Swift) you have to set the .attributeText like this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TheCell")!
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: message)
attributeString.addAttribute(NSStrikethroughStyleAttributeName, value: 2, range: NSMakeRange(0, attributeString.length))
cell.textLabel?.attributedText = attributeString
return cell
}
If you want to remove the strikethrough do this otherwise it will stick around!:
cell.textLabel?.attributedText = nil
I might be late to the party.
Anyway, I am aware about the NSMutableAttributedString but recently I achieved the same functionality with slightly different approach.
I added the UIView with height = 1.
Matched the leading and trailing constraints of the UIView with the label's leading and trailing constraints
Aligned the UIView at centre of the Label
After following all the above steps my Label, UIView and its constraints were looking like below image.
Swift5 UILabel Extension. Removing strikethrough sometimes doesn't work. Use this code in that case.
extension UILabel {
func strikeThrough(_ isStrikeThrough: Bool = true) {
guard let text = self.text else {
return
}
if isStrikeThrough {
let attributeString = NSMutableAttributedString(string: text)
attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: NSMakeRange(0,attributeString.length))
self.attributedText = attributeString
} else {
let attributeString = NSMutableAttributedString(string: text)
attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: [], range: NSMakeRange(0,attributeString.length))
self.attributedText = attributeString
}
}
}
Use below code
NSString* strPrice = #"£399.95";
NSMutableAttributedString *titleString = [[NSMutableAttributedString alloc] initWithString:strPrice];
[finalString addAttribute: NSStrikethroughStyleAttributeName value:[NSNumber numberWithInteger: NSUnderlineStyleSingle] range: NSMakeRange(0, [titleString length])];
self.lblOldPrice.attributedText = finalString;
Swift 4.2
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: product.price)
attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: NSMakeRange(0, attributeString.length))
lblPrice.attributedText = attributeString
Swift 5 - short version
let attributedText = NSAttributedString(
string: "Label Text",
attributes: [.strikethroughStyle: NSUnderlineStyle.single.rawValue]
)
yourLabel.attributedText = attributedText
Change the text property to attributed and select the text and right click to get the font property. Click on the strikethrough.
On iOS 10.3 has an issue on rendering strikethrough line fixes by Adding a NSBaselineOffsetAttributeName, as explained here, to the attributed string brings back the strikethrough line. Overriding drawText:in: can be slow especially on Collection View or Table View Cells.
One sol - Add view to render a line.
Second sol -
attributeString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: 2, range: NSMakeRange(0, attributeString.length))
attributeString.addAttribute(NSAttributedString.Key.baselineOffset, value: 2, range: NSMakeRange(0, attributeString.length))```
Swift 4 and 5
extension NSAttributedString {
/// Returns a new instance of NSAttributedString with same contents and attributes with strike through added.
/// - Parameter style: value for style you wish to assign to the text.
/// - Returns: a new instance of NSAttributedString with given strike through.
func withStrikeThrough(_ style: Int = 1) -> NSAttributedString {
let attributedString = NSMutableAttributedString(attributedString: self)
attributedString.addAttribute(.strikethroughStyle,
value: style,
range: NSRange(location: 0, length: string.count))
return NSAttributedString(attributedString: attributedString)
}
}
Example
let example = NSAttributedString(string: "440").withStrikeThrough(1)
myLabel.attributedText = example
Results
For those who face issue with multi line text strike
let attributedString = NSMutableAttributedString(string: item.name!)
//necessary if UILabel text is multilines
attributedString.addAttribute(NSBaselineOffsetAttributeName, value: 0, range: NSMakeRange(0, attributedString.length))
attributedString.addAttribute(NSStrikethroughStyleAttributeName, value: NSNumber(value: NSUnderlineStyle.styleSingle.rawValue), range: NSMakeRange(0, attributedString.length))
attributedString.addAttribute(NSStrikethroughColorAttributeName, value: UIColor.darkGray, range: NSMakeRange(0, attributedString.length))
cell.lblName.attributedText = attributedString
Create String extension and add below method
static func makeSlashText(_ text:String) -> NSAttributedString {
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: text)
attributeString.addAttribute(NSStrikethroughStyleAttributeName, value: 2, range: NSMakeRange(0, attributeString.length))
return attributeString
}
then use for your label like this
yourLabel.attributedText = String.makeSlashText("Hello World!")
This is the one you can use in Swift 4 because NSStrikethroughStyleAttributeName has been changed to NSAttributedStringKey.strikethroughStyle
let attributeString: NSMutableAttributedString = NSMutableAttributedString(string: "Your Text")
attributeString.addAttribute(NSAttributedStringKey.strikethroughStyle, value: 2, range: NSMakeRange(0, attributeString.length))
self.lbl.attributedText = attributeString

Resources