UITextView linkTextAttributes атрибут шрифта не применяется к NSAttributedString
У меня есть NSAttributedString
, сгенерированный из HTML, который содержит некоторые ссылки. Присвоенная строка показана в UITextView. Я хочу применить другой стиль шрифта для ссылок, и для этого устанавливаю linkTextAttributes
. Я добавил NSForegroundColorAttributeName
, NSFontAttributeName
и NSUnderlineStyleAttributeName
. По какой-то причине применяется цвет переднего плана, но остальные атрибуты отсутствуют.
myTextView.linkTextAttributes = [NSForegroundColorAttributeName : UIColor.redColor(), NSFontAttributeName : textLinkFont, NSUnderlineStyleAttributeName : NSUnderlineStyle.StyleNone.rawValue]
Кто-нибудь еще сталкивался с этим и как мне изменить стиль шрифта для ссылок, не применяя встроенный CSS к исходному HTML? Спасибо.
Ответы
Ответ 1
Не уверен, почему linkTextAttributes не работает для имени шрифта. Но мы можем достичь этого путем обновления атрибутов ссылки NSAttributedString. Проверьте код ниже.
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 {
}
Это код объективного 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]()
Ответ 2
По какой-то причине постобработка, связанная с строкой с enumerateAttributesInRange:
, не работает для меня.
Поэтому я использовал NSDataDetector
для обнаружения ссылки и enumerateMatchesInString:options:range:usingBlock:
, чтобы поместить мой стиль для всех ссылок в строке.
Вот моя функция обработки:
+ (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
Это быстрое обновление 3 ответа от @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]
Это быстрое решение для @CTiPKA, которое я предпочитаю, поскольку оно позволяет избежать 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
Ответ 4
Обновлено для 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
Ответ 5
для простых случаев: (без ужасного использования HTML):
let linkTextAttributes : [String : Any] = [
NSForegroundColorAttributeName: UIColor.red,
NSUnderlineColorAttributeName: UIColor.magenta,
NSUnderlineStyleAttributeName: NSUnderlineStyle.patternSolid.rawValue
]
self.infoText.linkTextAttributes = linkTextAttributes
Ответ 6
Также существует простой способ применить стиль для текста, если вы используете html - вы можете просто добавить стиль в HTML-код. Тогда вам не нужно беспокоиться об установке атрибутов для текста. Например:
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];
Ответ 7
Свифт 5 версия Райана Хайтнера офигенный ответ:
guard let attributedString = textView.attributedText else { return }
guard let linkFont = UIFont(name: "HelveticaNeue-Bold", size: 20.0) 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(NSAttributedString.Key.font, range: matchRange)
newString.addAttribute(NSAttributedString.Key.font, value: linkFont, range: matchRange)
}
})
textView.attributedText = newString