J'ai une NSAttributedString
générée à partir de HTML qui inclut des liens. La chaîne attribuée est affichée dans une UITextView. Je souhaite appliquer un style de police différent pour les liens et définir linkTextAttributes
pour cela. J'ai ajouté NSForegroundColorAttributeName
, NSFontAttributeName
et NSUnderlineStyleAttributeName
. Pour une raison quelconque, la couleur de premier plan est appliquée, mais pas les attributs restants.
myTextView.linkTextAttributes = [NSForegroundColorAttributeName : UIColor.redColor(), NSFontAttributeName : textLinkFont, NSUnderlineStyleAttributeName : NSUnderlineStyle.StyleNone.rawValue]
Quelqu'un d'autre a-t-il rencontré ce problème et comment puis-je changer le style de police pour les liens sans avoir à appliquer le code CSS en ligne au code HTML d'origine? Merci.
Vous ne savez pas pourquoi linkTextAttributes ne fonctionne pas pour le nom de la police. Mais nous pouvons y parvenir en mettant à jour les attributs de lien de NSAttributedString. Vérifiez le code ci-dessous.
do {
let htmlStringCode = "For more info <a href=\"http://www.samplelink.com/subpage.php?id=8\">Click here</a>"
let string = try NSAttributedString(data: htmlStringCode.dataUsingEncoding(NSUTF8StringEncoding)!, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding], documentAttributes: nil)
let newString = NSMutableAttributedString(attributedString: string)
string.enumerateAttributesInRange(NSRange.init(location: 0, length: string.length), options: .Reverse) { (attributes : [String : AnyObject], range:NSRange, _) -> Void in
if let _ = attributes[NSLinkAttributeName] {
newString.removeAttribute(NSFontAttributeName, range: range)
newString.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(30), range: range)
}
}
textField.attributedText = newString
textField.linkTextAttributes = [NSForegroundColorAttributeName : UIColor.redColor(), NSUnderlineStyleAttributeName : NSUnderlineStyle.StyleNone.rawValue]
}catch {
}
Voici le code objectif-C :
NSDictionary *options = @{NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType};
NSData *data = [html dataUsingEncoding:NSUnicodeStringEncoding allowLossyConversion:NO];
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:data options:options documentAttributes:nil error:nil];
NSMutableAttributedString *attributedStringWithBoldLinks = [[NSMutableAttributedString alloc] initWithAttributedString:attributedString];
[attributedString enumerateAttributesInRange:NSMakeRange(0, attributedString.string.length) options:NSAttributedStringEnumerationReverse usingBlock:^(NSDictionary<NSString *,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
if ([attrs objectForKey:NSLinkAttributeName]) {
[attributedStringWithBoldLinks removeAttribute:NSFontAttributeName range:range];
[attributedStringWithBoldLinks addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"YourFont-Bold" size:16.0] range:range];
}
}];
self.linkTextAttributes = @{NSForegroundColorAttributeName : [UIColor redColor]};
self.attributedText = attributedStringWithBoldLinks;
Pour une raison quelconque, le post-traitement attribué à la chaîne avec enumerateAttributesInRange:
ne fonctionne pas pour moi.
J'ai donc utilisé NSDataDetector
pour détecter link et enumerateMatchesInString:options:range:usingBlock:
pour mettre mon style pour tous les liens dans string. Voici ma fonction de traitement:
+ (void) postProcessTextViewLinksStyle:(UITextView *) textView {
NSAttributedString *attributedString = textView.attributedText;
NSMutableAttributedString *attributedStringWithItalicLinks = [[NSMutableAttributedString alloc] initWithAttributedString:attributedString];
NSError *error = nil;
NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink
error:&error];
[detector enumerateMatchesInString:[attributedString string]
options:0
range:NSMakeRange(0, [attributedString length])
usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){
NSRange matchRange = [match range];
NSLog(@"Links style postprocessing. Range (from: %lu, length: %lu )", (unsigned long)matchRange.location, (unsigned long)matchRange.length);
if ([match resultType] == NSTextCheckingTypeLink) {
[attributedStringWithItalicLinks removeAttribute:NSFontAttributeName range:matchRange];
[attributedStringWithItalicLinks addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"YourFont-Italic" size:14.0f] range:matchRange];
}
}];
textView.attributedText = attributedStringWithItalicLinks;
}
Ceci est une mise à jour de Swift 3 de la réponse ci-dessus de @Arun Ammannaya
guard let font = UIFont.init(name: "Roboto-Regular", size: 15) else {
return
}
let newString = NSMutableAttributedString(attributedString: string)
let range = NSRange(location:0,length: string.length)
string.enumerateAttributes(in: range, options: .reverse, using: { (attributes : [String : Any], range : NSRange, _) -> Void in
if let _ = attributes[NSLinkAttributeName] {
newString.removeAttribute(NSFontAttributeName, range: range)
newString.addAttribute(NSFontAttributeName, value: font, range: range)
}
})
errorTextView.attributedText = newString
errorTextView.linkTextAttributes = [NSForegroundColorAttributeName : UIColor.green, NSUnderlineStyleAttributeName : NSUnderlineStyle.styleSingle.rawValue]
Ceci est une solution Swift 3 à @CTiPKA que je préfère car elle évite HTML
guard let attributedString = errorTextView.attributedText else {
return
}
guard let font = UIFont.init(name: "Roboto-Regular", size: 15) else {
return
}
let newString = NSMutableAttributedString(attributedString: attributedString)
let types: NSTextCheckingResult.CheckingType = [.link, .phoneNumber]
guard let linkDetector = try? NSDataDetector(types: types.rawValue) else { return }
let range = NSRange(location:0,length: attributedString.length)
linkDetector.enumerateMatches(in: attributedString.string, options: [], range: range, using: { (match : NSTextCheckingResult?,
flags : NSRegularExpression.MatchingFlags, stop) in
if let matchRange = match?.range {
newString.removeAttribute(NSFontAttributeName, range: matchRange)
newString.addAttribute(NSFontAttributeName, value: font, range: matchRange)
}
})
errorTextView.attributedText = newString
Mis à jour pour Swift 4:
let originalText = NSMutableAttributedString(attributedString: textView.attributedText)
var newString = NSMutableAttributedString(attributedString: textView.attributedText)
originalText.enumerateAttributes(in: NSRange(0..<originalText.length), options: .reverse) { (attributes, range, pointer) in
if let _ = attributes[NSAttributedString.Key.link] {
newString.removeAttribute(NSAttributedString.Key.font, range: range)
newString.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: 30), range: range)
}
}
self.textView.attributedText = newString // updates the text view on the vc
pour des cas simples: (sans utilisation horrible du HTML):
let linkTextAttributes : [String : Any] = [
NSForegroundColorAttributeName: UIColor.red,
NSUnderlineColorAttributeName: UIColor.Magenta,
NSUnderlineStyleAttributeName: NSUnderlineStyle.patternSolid.rawValue
]
self.infoText.linkTextAttributes = linkTextAttributes
Il existe également un moyen simple d'appliquer un style au texte si vous utilisez le langage HTML: vous pouvez simplement ajouter le style dans le code html. Dans ce cas, vous n'avez pas à vous soucier de la définition d'attributs pour le texte. Par exemple:
NSString *html = [NSString stringWithFormat:@"<p style=\"font-family: Your-Font-Name; color: #344052; font-size: 15px\"><a style=\"color: #0A9FD2\" href=\"https://examplelink.com\">%@</a> %@ on %@</p>", name, taskName, timeString];
NSDictionary *options = @{NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType};
NSData *data = [html dataUsingEncoding:NSUTF8StringEncoding];
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:data options:options documentAttributes:nil error:nil];