Разбор HTML в NSAttributedText-как установить шрифт?
Я пытаюсь получить фрагмент текста, который отформатирован в html для отображения красиво на iPhone в UITableViewCell.
пока у меня есть это:
NSError* error;
NSString* source = @"<strong>Nice</strong> try, Phil";
NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithData:[source dataUsingEncoding:NSUTF8StringEncoding]
options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]}
documentAttributes:nil error:&error];
данный вид работ. Я получаю текст, который имеет "хороший" жирным шрифтом! Но... он также устанавливает шрифт, чтобы быть Times Roman! Это не тот шрифт, который я хочу.
Я думаю, что мне нужно установить что-то в documentAttributes, но, я не могу найти никаких примеров нигде.
13 ответов:
#import "UILabel+HTML.h" @implementation UILabel (HTML) - (void)jaq_setHTMLFromString:(NSString *)string { string = [string stringByAppendingString:[NSString stringWithFormat:@"<style>body{font-family: '%@'; font-size:%fpx;}</style>", self.font.fontName, self.font.pointSize]]; self.attributedText = [[NSAttributedString alloc] initWithData:[string dataUsingEncoding:NSUnicodeStringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)} documentAttributes:nil error:nil]; } @endтаким образом, вам не нужно указывать, какой шрифт вы хотите, он будет принимать шрифт метки и размер.
Swift версия, основанная на ответе, данном Javier Querol
extension UILabel { func setHTMLFromString(text: String) { let modifiedFont = NSString(format:"<span style=\"font-family: \(self.font!.fontName); font-size: \(self.font!.pointSize)\">%@</span>", text) as String let attrStr = try! NSAttributedString( data: modifiedFont.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: true)!, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding], documentAttributes: nil) self.attributedText = attrStr } }Swift 3.0 и iOS 9+
extension UILabel { func setHTMLFromString(htmlText: String) { let modifiedFont = String(format:"<span style=\"font-family: '-apple-system', 'HelveticaNeue'; font-size: \(self.font!.pointSize)\">%@</span>", htmlText) //process collection values let attrStr = try! NSAttributedString( data: modifiedFont.data(using: .unicode, allowLossyConversion: true)!, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil) self.attributedText = attrStr } }
разобрался. Немного медведь, и, возможно, не лучший ответ.
этот код будет проходить через все изменения шрифта. Я знаю, что он использует "Times New Roman" и "Times New Roman BoldMT" для шрифтов. Но независимо от этого, это найдет жирные шрифты и позволит мне сбросить их. Я также могу сбросить размер, пока я на нем.
Я честно надеюсь / думаю, что есть способ настроить это во время разбора, но я не могу найти его, если есть.
NSRange range = (NSRange){0,[str length]}; [str enumerateAttribute:NSFontAttributeName inRange:range options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired usingBlock:^(id value, NSRange range, BOOL *stop) { UIFont* currentFont = value; UIFont *replacementFont = nil; if ([currentFont.fontName rangeOfString:@"bold" options:NSCaseInsensitiveSearch].location != NSNotFound) { replacementFont = [UIFont fontWithName:@"HelveticaNeue-CondensedBold" size:25.0f]; } else { replacementFont = [UIFont fontWithName:@"HelveticaNeue-Thin" size:25.0f]; } [str addAttribute:NSFontAttributeName value:replacementFont range:range]; }];
Я действительно нашел рабочее решение этой проблемы:
изменение шрифта в строке ответа HTML, прежде чем он будет проанализирован.
NSString *aux = [NSString stringWithFormat:@"<span style=\"font-family: YOUR_FONT_NAME; font-size: SIZE\">%@</span>", htmlResponse];пример:
NSString *aux = [NSString stringWithFormat:@"<span style=\"font-family: HelveticaNeue-Thin; font-size: 17\">%@</span>", [response objectForKey:@"content"]];Swift версия:
let aux = "<span style=\"font-family: YOUR_FONT_NAME; font-size: SIZE\">\(htmlResponse)</span>"
более общий подход заключается в том, чтобы посмотреть на признаки шрифта при перечислении и создать шрифт с теми же признаками (полужирный, курсив и т. д.):
extension NSMutableAttributedString { /// Replaces the base font (typically Times) with the given font, while preserving traits like bold and italic func setBaseFont(baseFont: UIFont, preserveFontSizes: Bool = false) { let baseDescriptor = baseFont.fontDescriptor let wholeRange = NSRange(location: 0, length: length) beginEditing() enumerateAttribute(.font, in: wholeRange, options: []) { object, range, _ in guard let font = object as? UIFont else { return } // Instantiate a font with our base font's family, but with the current range's traits let traits = font.fontDescriptor.symbolicTraits guard let descriptor = baseDescriptor.withSymbolicTraits(traits) else { return } let newSize = preserveFontSizes ? descriptor.pointSize : baseDescriptor.pointSize let newFont = UIFont(descriptor: descriptor, size: newSize) self.removeAttribute(.font, range: range) self.addAttribute(.font, value: newFont, range: range) } endEditing() } }
Да, есть более простое решение. Установите шрифт в источнике html!
NSError* error; NSString* source = @"<strong>Nice</strong> try, Phil"; source = [source stringByAppendingString:@"<style>strong{font-family: 'Avenir-Roman';font-size: 14px;}</style>"]; NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithData:[source dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]} documentAttributes:nil error:&error];надеюсь, что это помогает.
Swift 4+ обновление UILabel расширение
extension UILabel { func setHTMLFromString(text: String) { let modifiedFont = NSString(format:"<span style=\"font-family: \(self.font!.fontName); font-size: \(self.font!.pointSize)\">%@</span>" as NSString, text) let attrStr = try! NSAttributedString( data: modifiedFont.data(using: String.Encoding.unicode.rawValue, allowLossyConversion: true)!, options: [NSAttributedString.DocumentReadingOptionKey.documentType:NSAttributedString.DocumentType.html, NSAttributedString.DocumentReadingOptionKey.characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil) self.attributedText = attrStr } }iOS 9+
extension UILabel { func setHTMLFromString(htmlText: String) { let modifiedFont = NSString(format:"<span style=\"font-family: '-apple-system', 'HelveticaNeue'; font-size: \(self.font!.pointSize)\">%@</span>" as NSString, htmlText) as String //process collection values let attrStr = try! NSAttributedString( data: modifiedFont.data(using: .unicode, allowLossyConversion: true)!, options: [NSAttributedString.DocumentReadingOptionKey.documentType:NSAttributedString.DocumentType.html, NSAttributedString.DocumentReadingOptionKey.characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil) self.attributedText = attrStr } }
ответы выше всего работают нормально, если вы делаете преобразование одновременно с созданием
NSAttributedString. Но я думаю, что лучшим решением, которое работает на самой строке и поэтому не нуждается в доступе к входу, является следующая категория:extension NSMutableAttributedString { func convertFontTo(font: UIFont) { var range = NSMakeRange(0, 0) while (NSMaxRange(range) < length) { let attributes = attributesAtIndex(NSMaxRange(range), effectiveRange: &range) if let oldFont = attributes[NSFontAttributeName] { let newFont = UIFont(descriptor: font.fontDescriptor().fontDescriptorWithSymbolicTraits(oldFont.fontDescriptor().symbolicTraits), size: font.pointSize) addAttribute(NSFontAttributeName, value: newFont, range: range) } } } }как использовать:
let desc = NSMutableAttributedString(attributedString: *someNSAttributedString*) desc.convertFontTo(UIFont.systemFontOfSize(16))работает на iOS 7+
использование nshtmltextdocumenttype является медленным и трудно контролировать стили. Я предлагаю вам попробовать мою библиотеку, которая называется атрибутика. Он имеет свой собственный очень быстрый парсер. Также вы можете иметь любые имена тегов и определить подходящий стиль для них.
пример:
let str = "<strong>Nice</strong> try, Phil".style(tags: Style("strong").font(.boldSystemFont(ofSize: 15))).attributedString label.attributedText = strвы можете найти его здесь https://github.com/psharanda/Atributika
улучшение решения Виктора, включая цвет:
extension UILabel { func setHTMLFromString(text: String) { let modifiedFont = NSString(format:"<span style=\"color:\(self.textColor.toHexString());font-family: \(self.font!.fontName); font-size: \(self.font!.pointSize)\">%@</span>", text) as String let attrStr = try! NSAttributedString( data: modifiedFont.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: true)!, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding], documentAttributes: nil) self.attributedText = attrStr } }для этого Вам также понадобится YLColor.swift преобразования uicolor в hexhttps://gist.github.com/yannickl/16f0ed38f0698d9a8ae7
Спасибо за ответы, мне очень понравилось расширение, но я еще не преобразован в swift. Для тех старых школьников, которые все еще находятся в Objective-C, это должно немного помочь :D
-(void) setBaseFont:(UIFont*)font preserveSize:(BOOL) bPreserve { UIFontDescriptor *baseDescriptor = font.fontDescriptor; [self enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, [self length]) options:0 usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) { UIFont *font = (UIFont*)value; UIFontDescriptorSymbolicTraits traits = font.fontDescriptor.symbolicTraits; UIFontDescriptor *descriptor = [baseDescriptor fontDescriptorWithSymbolicTraits:traits]; UIFont *newFont = [UIFont fontWithDescriptor:descriptor size:bPreserve?baseDescriptor.pointSize:descriptor.pointSize]; [self removeAttribute:NSFontAttributeName range:range]; [self addAttribute:NSFontAttributeName value:newFont range:range]; }]; }Удачи В Кодировании! -- Грег Кадр
Swift 3 расширение строки, включая шрифт nil. Свойство без шрифта берется из другого так вопрос, не помню какой: (
extension String { var html2AttributedString: NSAttributedString? { guard let data = data(using: .utf8) else { return nil } do { return try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil) } catch { print(error.localizedDescription) return nil } } public func getHtml2AttributedString(font: UIFont?) -> NSAttributedString? { guard let font = font else { return html2AttributedString } let modifiedString = "<style>body{font-family: '\(font.fontName)'; font-size:\(font.pointSize)px;}</style>\(self)"; guard let data = modifiedString.data(using: .utf8) else { return nil } do { return try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil) } catch { print(error) return nil } } }
на самом деле, существует еще более простой и чистый способ. Просто установите шрифт после разбора HTML:
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUTF8StringEncoding] options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)} documentAttributes:nil error:nil]; [text addAttributes:@{NSFontAttributeName: [UIFont fontWithName:@"Lato-Regular" size:20]} range:NSMakeRange(0, text.length)];
Comments