Underline part of a string using NSMutableAttributedString in iOS 8 is not working
Solution 1
Update: By investigating this question: Displaying NSMutableAttributedString on iOS 8 I finally found the solution!
You should add NSUnderlineStyleNone at the beginning of the string.
Swift 4.2 (none
was removed):
let attributedString = NSMutableAttributedString()
attributedString.append(NSAttributedString(string: "test ",
attributes: [.underlineStyle: 0]))
attributedString.append(NSAttributedString(string: "s",
attributes: [.underlineStyle: NSUnderlineStyle.single.rawValue]))
attributedString.append(NSAttributedString(string: "tring",
attributes: [.underlineStyle: 0]))
Objective-C:
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init];
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:@"test "
attributes:@{NSUnderlineStyleAttributeName: @(NSUnderlineStyleNone)}]];
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:@"s"
attributes:@{NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle),
NSBackgroundColorAttributeName: [UIColor clearColor]}]];
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:@"tring"]];
Another bonus of such approach is absence of any ranges. Very nice for localized strings.
Seems like it is Apple bug :(
Solution 2
I found that if you apply UnderlineStyleNone to the whole string you can then selectively apply underline to a part that starts in the middle:
func underlinedString(string: NSString, term: NSString) -> NSAttributedString {
let output = NSMutableAttributedString(string: string)
let underlineRange = string.rangeOfString(term)
output.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.StyleNone.rawValue, range: NSMakeRange(0, string.length))
output.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.StyleSingle.rawValue, range: underlineRange)
return output
}
Solution 3
NSMutableAttributedString *signUpString = [[NSMutableAttributedString alloc] initWithString:@"Not a member yet?Sign Up now"];
[signUpString appendAttributedString:[[NSAttributedString alloc] initWithString:@" "attributes:@{NSUnderlineStyleAttributeName: @(NSUnderlineStyleNone)}]];
[signUpString addAttributes: @{NSForegroundColorAttributeName:UIColorFromRGB(0x43484B),NSUnderlineStyleAttributeName:[NSNumber numberWithInteger:NSUnderlineStyleSingle]} range:NSMakeRange(17,11)];
signUpLbl.attributedText = [signUpString copy];
It worked for me
Solution 4
It's September 2018, so this answer is not about iOS8 but it still relates to underlining part of a string.
Here is a Swift 4 extension that underlines a given term within an already composed myAttributedString
extension NSMutableAttributedString {
func underline(term: String) {
guard let underlineRange = string.range(of: term) else {
return
}
let startPosition = string.distance(from: term.startIndex, to: underlineRange.lowerBound)
let nsrange = NSRange(location: startPosition, length: term.count)
addAttribute(
.underlineStyle,
value: NSUnderlineStyle.styleSingle.rawValue,
range: nsrange)
}
}
Usage: myAttributedString.underline(term: "some term")
Solution 5
Swift 5 version of @Joss's answer with few modifications, by adding a returned NSMutableAttributedString, because I couldn't use the original solution without it.
extension NSMutableAttributedString {
func underline(term: String) -> NSMutableAttributedString {
guard let underlineRange = string.range(of: term) else {
return NSMutableAttributedString()
}
let startPosition = string.distance(from: term.startIndex, to: underlineRange.lowerBound)
let nsrange = NSRange(location: startPosition, length: term.count)
addAttribute(
.underlineStyle,
value: NSUnderlineStyle.single.rawValue,
range: nsrange)
return self
}
}
Usage:
let myUnderLinedText = "Hello World"
let underLinedMutableString = NSMutableAttributedString(string: myUnderLinedText, attributes: titleAttributes).underline(term: myUnderLinedText)
KlimczakM
Full Stack Mobile Developer eager to learn new things. #iOS #Swift #Android #Kotlin
Updated on July 08, 2022Comments
-
KlimczakM almost 2 years
I try to underline part of a string, for example, a 'string' part in 'test string' string. I'm using
NSMutableAttributedString
and my solution was working well oniOS7
.NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"test string"]; [attributedString addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:NSMakeRange(5, 6)]; myLabel.attributedText = attributedString;
The problem is that my solution is not working in
iOS8
anymore. After spending an hour on testing multiple variants ofNSMutableAttributedString
, I found out that this solution works only when range starts with 0 (length can differ). What is the reason for that? How can I workaround this? -
KlimczakM over 9 yearsI thought it was working, but unfortunately I ran the app in 7.1 simulator... Still not working on iOS8. But avoiding range is very nice, thanks!
-
kelin over 9 yearsTo be honest, I didn't tested my code on iOS 8. But now I've done, and have finally found the solution.
-
pvshnik over 9 yearsThanks. This really saved my time!
-
H Raval over 7 yearshow can remove underline after add
-
H Raval over 7 yearshow can remove underline after add
-
kelin over 7 years@HRaval, create a new string without underline.
-
H Raval over 7 yearsbut how can i direct text is underlined or not?
-
Jeremy Piednoel over 5 yearshey @kelin thanks for this answer. Just a small correction
.underlineStyle: NSUnderlineStyle.single.rawValue,
-
kelin over 5 years@JeremyPiednoel, big thanks! Updated the answer for Swift 4.2.