web-dev-qa-db-fra.com

Attribut de police UITextView linkTextAttributes non appliqué à NSAttributedString

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.

12
lostInTransit

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;

 Screenshot

18
Arun Ammannaya

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;
}
3
CTiPKA

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
2
Ryan Heitner

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
2
Adam Neuwirth

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
2
ingconti

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];
0
huong