将 HTML 解析为 NSAttributedText - 如何设置字体?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19921972/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 15:15:00  来源:igfitidea点击:

Parsing HTML into NSAttributedText - how to set font?

htmliosnsattributedstring

提问by phil

I am trying to get a snippet of text that is formatted in html to display nicely on an iPhone in a UITableViewCell.

我正在尝试获取以 html 格式设置的文本片段,以便在 UITableViewCell 中的 iPhone 上很好地显示。

So far I have this:

到目前为止,我有这个:

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

This kind of works. I get some text that has 'Nice' in bold! But... it also sets the font to be Times Roman! This is not the font face I want. I am thinking I need to set something in the documentAttributes, but, I can't find any examples anywhere.

这种作品。我收到一些以粗体显示“Nice”的文本!但是......它还将字体设置为Times Roman!这不是我想要的字体。我想我需要在 documentAttributes 中设置一些东西,但是,我在任何地方都找不到任何示例。

采纳答案by phil

Figured it out. Bit of a bear, and maybe not the best answer.

弄清楚了。有点熊,也许不是最好的答案。

This code will go through all the font changes. I know that it is using "Times New Roman" and "Times New Roman BoldMT" for the fonts. But regardless, this will find the bold fonts and let me reset them. I can also reset the size while I'm at it.

此代码将经历所有字体更改。我知道它使用“Times New Roman”和“Times New Roman BoldMT”作为字体。但无论如何,这将找到粗体并让我重置它们。我也可以在使用时重置大小。

I honestly hope/think there is a way to set this up at parse time, but I can't find it if there is.

老实说,我希望/认为有一种方法可以在解析时进行设置,但是如果有的话我找不到。

    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];
    }];

回答by Víctor Albertos

Swift 2version, based on the answer given by Javier Querol

Swift 2版本,基于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 and iOS 9+

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)

        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 and iOS 11+

Swift 5 和 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
    }
}

回答by Javier Querol

#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

This way you don't need to specify which font you want, it will take the label font and size.

这样你就不需要指定你想要的字体,它将采用标签字体和大小。

回答by Teodor Ciuraru

I actually found a working solution to this problem:

我实际上找到了解决这个问题的有效方法:

Changing the font in your HTML response string before it gets parsed.

在解析之前更改 HTML 响应字符串中的字体。

NSString *aux = [NSString stringWithFormat:@"<span style=\"font-family: YOUR_FONT_NAME; font-size: SIZE\">%@</span>", htmlResponse];

Example:

例子:

NSString *aux = [NSString stringWithFormat:@"<span style=\"font-family: HelveticaNeue-Thin; font-size: 17\">%@</span>", [response objectForKey:@"content"]];

Swift version:

迅捷版:

let aux = "<span style=\"font-family: YOUR_FONT_NAME; font-size: SIZE\">\(htmlResponse)</span>"

回答by markiv

A more generic approach is to look at the font traits while enumerating, and create a font with the same traits (bold, italic, etc.):

更通用的方法是在枚举时查看字体特征,并创建具有相同特征(粗体、斜体等)的字体:

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()
    }
}

回答by Max

Yes, there is an easier solution. Set the font in the html source!

是的,有一个更简单的解决方案。在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];

Hope this helps.

希望这可以帮助。

回答by Rafat touqir Rafsun

Swift 4+update of UILabelextension

UILabel扩展的Swift 4+更新

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+

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
    }
}

回答by HughHughTeotl

The answers above all work OK if you're doing the conversion at the same time as creating the NSAttributedString. But I think a better solution, which works on the string itself and therefore doesn't need access to the input, is the following category:

如果您在创建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)
            }
        }
    }
}

Use as:

用于:

let desc = NSMutableAttributedString(attributedString: *someNSAttributedString*)
desc.convertFontTo(UIFont.systemFontOfSize(16))

Works on iOS 7+

适用于 iOS 7+

回答by Juan Carlos Ospina Gonzalez

Improving on Victor's solution, including color:

改进 Victor 的解决方案,包括颜色:

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
      }
  }

For this to work you will also need YLColor.swift of the uicolor to hex conversion https://gist.github.com/yannickl/16f0ed38f0698d9a8ae7

为此,您还需要 uicolor 到十六进制转换的 YLColor.swift https://gist.github.com/yannickl/16f0ed38f0698d9a8ae7

回答by Pavel Sharanda

Using of NSHTMLTextDocumentType is slow and hard to control styles. I suggest you to try my library which is called Atributika. It has its own very fast parser. Also you can have any tag names and define any style for them.

使用 NSHTMLTextDocumentType 速度慢且难以控制样式。我建议你试试我的名为 Atributika 的库。它有自己的非常快速的解析器。您也可以拥有任何标签名称并为它们定义任何样式。

Example:

例子:

let str = "<strong>Nice</strong> try, Phil".style(tags:
    Style("strong").font(.boldSystemFont(ofSize: 15))).attributedString

label.attributedText = str

You can find it here https://github.com/psharanda/Atributika

你可以在这里找到它https://github.com/psharanda/Atributika