J'essaie de souligner une partie de chaîne, par exemple une chaîne ' string ' dans ' test string '. J'utilise NSMutableAttributedString
et ma solution fonctionnait bien avec iOS7
.
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]
initWithString:@"test string"];
[attributedString addAttribute:NSUnderlineStyleAttributeName
value:@(NSUnderlineStyleSingle)
range:NSMakeRange(5, 6)];
myLabel.attributedText = attributedString;
Le problème est que ma solution ne fonctionne plus dans iOS8
. Après avoir passé une heure à tester plusieurs variantes de NSMutableAttributedString
, j'ai découvert que cette solution ne fonctionne que lorsque la plage commence par 0 (la longueur peut varier). Quelle est la raison de ceci? Comment puis-je contourner ce problème?
Mise à jour: En examinant cette question: Afficher NSMutableAttributedString sur iOS 8 J'ai enfin trouvé la solution!
Vous devez ajouter NSUnderlineStyleNone au début de la chaîne.
Swift 4.2 (none
a été supprimé):
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]))
Objectif 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"]];
Un autre avantage d'une telle approche est l'absence de toute plage. Très agréable pour les chaînes localisées.
On dirait qu'il s'agit d'un bug Apple :(
J'ai constaté que si vous appliquez UnderlineStyleNone à la chaîne entière, vous pouvez ensuite appliquer de manière sélective le soulignement à une partie commençant au milieu:
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
}
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];
Ça a fonctionné pour moi
version de Swift 5 de la réponse de @ Joss avec peu de modifications, en ajoutant un NSMutableAttributedString renvoyé, car je ne pourrais pas utiliser la solution originale sans ce dernier.
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)
J'ai utilisé l'extension suivante (en utilisant la fonction exidy) dans la plaine de jeux/le simulateur et cela a bien fonctionné, vous pouvez modifier/ajouter des attributs en fonction de vos besoins.
extension NSMutableAttributedString
{
func changeWordsColour(terms:[NSString])
{
let string = self.string as NSString
self.addAttribute(NSForegroundColorAttributeName, value: UIColor.brownColor(), range: NSMakeRange(0, self.length))
for term in terms
{
let underlineRange = string.rangeOfString(term as String)
self.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: underlineRange)
}
}
}
let myStr = NSMutableAttributedString(string: "Change Words Colour")
myStr.changeWordsColour(["change","Colour"])
Nous sommes en septembre 2018, donc cette réponse ne concerne pas iOS8, mais concerne toujours le soulignement d'une partie d'une chaîne.
Voici une extension Swift 4 qui souligne un terme donné dans un myAttributedString
déjà composé
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")