Próbuję uzyskać fragment tekstu sformatowany w html, aby ładnie wyświetlać się na iPhonie w UITableViewCell.
Jak dotąd mam to:
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];
Ten rodzaj działa. Otrzymuję tekst z pogrubioną czcionką „Nice”! Ale ... ustawia również czcionkę Times Roman! To nie jest krój czcionki, którego chcę. Myślę, że muszę coś ustawić w documentAttributes, ale nigdzie nie mogę znaleźć żadnych przykładów.
html
ios
nsattributedstring
phil
źródło
źródło
Odpowiedzi:
Wersja Swift 2 , oparta na odpowiedzi udzielonej przez Javiera Querola
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 i 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) let attrStr = try! NSAttributedString( data: modifiedFont.data(using: .unicode, allowLossyConversion: true)!, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil) self.attributedText = attrStr } }
Swift 5 i iOS 11+
extension UILabel { func setHTMLFromString(htmlText: String) { let modifiedFont = String(format:"<span style=\"font-family: '-apple-system', 'HelveticaNeue'; font-size: \(self.font!.pointSize)\">%@</span>", htmlText) let attrStr = try! NSAttributedString( data: modifiedFont.data(using: .unicode, allowLossyConversion: true)!, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding:String.Encoding.utf8.rawValue], documentAttributes: nil) self.attributedText = attrStr } }
źródło
font-family: '-apple-system', 'HelveticaNeue';
(który działa, a także jest wstecznie kompatybilny). Jeśli obsługujesz tylko iOS9,font-family: -apple-system;
możesz użyćcolor: #000000
. Zobacz ten link, aby przekonwertować UIColor na ciąg szesnastkowy: gist.github.com/yannickl/16f0ed38f0698d9a8ae7#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
W ten sposób nie musisz określać żądanej czcionki, przyjmie czcionkę i rozmiar etykiety.
źródło
NSUnicodeStringEncoding
a następnie kodujesz dane z powrotem do znaków za pomocąNSUTF8StringEncoding
. Czy to jest w porządku?Właściwie znalazłem działające rozwiązanie tego problemu:
Zmiana czcionki w ciągu odpowiedzi HTML, zanim zostanie on przeanalizowany.
NSString *aux = [NSString stringWithFormat:@"<span style=\"font-family: YOUR_FONT_NAME; font-size: SIZE\">%@</span>", htmlResponse];
Przykład:
NSString *aux = [NSString stringWithFormat:@"<span style=\"font-family: HelveticaNeue-Thin; font-size: 17\">%@</span>", [response objectForKey:@"content"]];
Wersja Swift:
let aux = "<span style=\"font-family: YOUR_FONT_NAME; font-size: SIZE\">\(htmlResponse)</span>"
źródło
Domyśliłam się. Trochę niedźwiedzia i może nie najlepsza odpowiedź.
Ten kod przejdzie przez wszystkie zmiany czcionek. Wiem, że używa czcionek „Times New Roman” i „Times New Roman BoldMT”. Ale niezależnie od tego, znajdzie to pogrubione czcionki i pozwól mi je zresetować. Mogę też zresetować rozmiar, gdy jestem przy tym.
Szczerze mam nadzieję / myślę, że jest sposób na skonfigurowanie tego w czasie parsowania, ale nie mogę go znaleźć, jeśli jest.
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]; }];
źródło
Bardziej ogólne podejście polega na przyjrzeniu się cechom czcionki podczas wyliczania i utworzeniu czcionki o takich samych cechach (pogrubienie, kursywa itp.):
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() } }
źródło
Tak, jest łatwiejsze rozwiązanie. Ustaw czcionkę w źródle 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];
Mam nadzieję że to pomoże.
źródło
Szybka aktualizacja 4+ rozszerzenia 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 } }
źródło
Odpowiedzi przede wszystkim działają OK, jeśli robisz konwersję w tym samym czasie, co tworzenie pliku
NSAttributedString
. Ale myślę, że lepszym rozwiązaniem, które działa na samym ciągu i dlatego nie wymaga dostępu do danych wejściowych, jest następująca kategoria: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) } } } }
Użyj jako:
let desc = NSMutableAttributedString(attributedString: *someNSAttributedString*) desc.convertFontTo(UIFont.systemFontOfSize(16))
Działa na iOS 7+
źródło
Ulepszanie rozwiązania Victora, w tym koloru:
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 } }
Aby to zadziałało, będziesz również potrzebować YLColor.swift konwersji uicolor na hex https://gist.github.com/yannickl/16f0ed38f0698d9a8ae7
źródło
Używanie NSHTMLTextDocumentType jest powolne i trudne do kontrolowania stylów. Proponuję wypróbować moją bibliotekę, która nazywa się Atributika. Posiada własny, bardzo szybki parser. Możesz także mieć dowolne nazwy tagów i zdefiniować dla nich dowolny styl.
Przykład:
let str = "<strong>Nice</strong> try, Phil".style(tags: Style("strong").font(.boldSystemFont(ofSize: 15))).attributedString label.attributedText = str
Możesz go znaleźć tutaj https://github.com/psharanda/Atributika
źródło
Łącząc odpowiedzi wszystkich, stworzyłem dwa rozszerzenia umożliwiające ustawienie etykiety z tekstem html. Niektóre powyższe odpowiedzi nie interpretowały poprawnie rodziny czcionek w przypisanych ciągach znaków. Inne były niekompletne dla moich potrzeb lub zawiodły w inny sposób. Daj mi znać, jeśli jest coś, co chciałbyś, abym ulepszył.
Mam nadzieję, że to komuś pomoże.
extension UILabel { /// Sets the label using the supplied html, using the label's font and font size as a basis. /// For predictable results, using only simple html without style sheets. /// See /programming/19921972/parsing-html-into-nsattributedtext-how-to-set-font /// /// - Returns: Whether the text could be converted. @discardableResult func setAttributedText(fromHtml html: String) -> Bool { guard let data = html.data(using: .utf8, allowLossyConversion: true) else { print(">>> Could not create UTF8 formatted data from \(html)") return false } do { let mutableText = try NSMutableAttributedString( data: data, options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html, NSAttributedString.DocumentReadingOptionKey.characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil) mutableText.replaceFonts(with: font) self.attributedText = mutableText return true } catch (let error) { print(">>> Could not create attributed text from \(html)\nError: \(error)") return false } } } extension NSMutableAttributedString { /// Replace any font with the specified font (including its pointSize) while still keeping /// all other attributes like bold, italics, spacing, etc. /// See /programming/19921972/parsing-html-into-nsattributedtext-how-to-set-font func replaceFonts(with font: UIFont) { let baseFontDescriptor = font.fontDescriptor var changes = [NSRange: UIFont]() enumerateAttribute(.font, in: NSMakeRange(0, length), options: []) { foundFont, range, _ in if let htmlTraits = (foundFont as? UIFont)?.fontDescriptor.symbolicTraits, let adjustedDescriptor = baseFontDescriptor.withSymbolicTraits(htmlTraits) { let newFont = UIFont(descriptor: adjustedDescriptor, size: font.pointSize) changes[range] = newFont } } changes.forEach { range, newFont in removeAttribute(.font, range: range) addAttribute(.font, value: newFont, range: range) } } }
źródło
UILabel
iUITextView
. dzięki!Dzięki za odpowiedzi, bardzo podobało mi się rozszerzenie, ale jeszcze nie przeszedłem na szybkie. Dla tych starych uczniów, którzy nadal uczą się w Objective-C, powinno to trochę pomó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]; }]; }
Miłego kodowania! --Greg Frame
źródło
Rozwiązanie Swift 5 dla UILabel i UITextView
extension UITextView { func setHTMLFromString(htmlText: String) { let modifiedFont = String(format:"<span style=\"font-family: '-apple-system', 'HelveticaNeue'; font-size: \(self.font!.pointSize)\">%@</span>", htmlText) let attrStr = try! NSAttributedString( data: modifiedFont.data(using: .unicode, allowLossyConversion: true)!, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding:String.Encoding.utf8.rawValue], documentAttributes: nil) self.attributedText = attrStr }
}
extension UILabel { func setHTMLFromString(htmlText: String) { let modifiedFont = String(format:"<span style=\"font-family: '-apple-system', 'HelveticaNeue'; font-size: \(self.font!.pointSize)\">%@</span>", htmlText) let attrStr = try! NSAttributedString( data: modifiedFont.data(using: .unicode, allowLossyConversion: true)!, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding:String.Encoding.utf8.rawValue], documentAttributes: nil) self.attributedText = attrStr }
}
Wykorzystanie dla UILabel
self.label.setHTMLFromString(htmlText: htmlString)
Użycie dla UITextView
self.textView.setHTMLFromString(htmlText: htmlString)
Wynik
źródło
Rozszerzenie Swift 3 String zawierające czcionkę zerową. Właściwość bez czcionki pochodzi z innego pytania SO, nie pamiętam, które :(
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 } } }
źródło
Oto rozszerzenie dla NSString, które zwraca NSAttributedString przy użyciu Objective-C.
Prawidłowo obsługuje ciąg z tagami HTML i ustawia żądaną czcionkę i kolor czcionki, zachowując tagi HTML, w tym BOLD, ITALICS ...
Co najlepsze, nie opiera się na żadnych znacznikach HTML do ustawiania atrybutów czcionki.
@implementation NSString (AUIViewFactory) - (NSAttributedString*)attributedStringFromHtmlUsingFont:(UIFont*)font fontColor:(UIColor*)fontColor { NSMutableAttributedString* mutableAttributedString = [[[NSAttributedString alloc] initWithData:[self dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute : @(NSUTF8StringEncoding)} documentAttributes:nil error:nil] mutableCopy]; // parse text with html tags into a mutable attributed string [mutableAttributedString beginEditing]; // html tags cause font ranges to be created, for example "This text is <b>bold</b> now." creates three font ranges: "This text is " , "bold" , " now." [mutableAttributedString enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, mutableAttributedString.length) options:0 usingBlock:^(id value, NSRange range, BOOL* stop) { // iterate every font range, change every font to new font but preserve symbolic traits such as bold and italic (underline and strikethorugh are preserved automatically), set font color if (value) { UIFont* oldFont = (UIFont*)value; UIFontDescriptor* fontDescriptor = [font.fontDescriptor fontDescriptorWithSymbolicTraits:oldFont.fontDescriptor.symbolicTraits]; UIFont* newFont = [UIFont fontWithDescriptor:fontDescriptor size:font.pointSize]; [mutableAttributedString removeAttribute:NSFontAttributeName range:range]; // remove the old font attribute from this range [mutableAttributedString addAttribute:NSFontAttributeName value:newFont range:range]; // add the new font attribute to this range [mutableAttributedString addAttribute:NSForegroundColorAttributeName value:fontColor range:range]; // set the font color for this range } }]; [mutableAttributedString endEditing]; return mutableAttributedString; } @end
źródło
Poniższe podejście działa. W tym podejściu możesz bardzo dobrze podać rodzinę czcionek, rozmiar i kolor czcionki. Zachęcamy do zasugerowania zmian lub lepszego sposobu na zrobienie tego.
extension UILabel { func setHTMLFromString(htmlText: String,fontFamily:String,fontColor:String) { let modifiedFont = String(format:"<span style=\"font-family: '-apple-system', \(fontFamily); font-size: \(self.font!.pointSize); color: \(fontColor) ; \">%@</span>", htmlText) do{ if let valData = modifiedFont.data(using: .utf8){ let attrStr = try NSAttributedString(data: valData, options: [NSAttributedString.DocumentReadingOptionKey.documentType : NSAttributedString.DocumentType.html.rawValue], documentAttributes: nil) self.attributedText = attrStr } } catch{ print("Conversion failed with \(error)") self.attributedText = nil } } }
źródło
Właściwie istnieje jeszcze łatwiejszy i czystszy sposób. Po prostu ustaw czcionkę po przeanalizowaniu kodu 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)];
źródło