Swift-在具有自己样式的HTMLstring上更改字体

我正在从Wordpress API中获取一个HTMLstring,并将其parsing为一个Attributed String以在我的应用程序中显示它。 由于string有自己的样式,它显示不同的字体和大小,这是影响我们的deviseselect。

我想要做的是改变整个属性string的字体和大小。

我试图在属性string的选项中这样做,但它什么都不做:

let attributedT = try! NSAttributedString( data: nContent!.decodeHTML().data(using: String.Encoding.unicode, allowLossyConversion: true)!, options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSFontAttributeName: UIFont(name: "Helvetica", size: 16.0)!], documentAttributes: nil) contentLbl.attributedText = attributedT 

有没有人有任何想法如何实现这一目标?

PS我知道我可以添加一个CSS标签的string的开始或结束,但这会覆盖其他的风格呢? 另外,如果这是一个有效的解决scheme,请提供一个关于如何做的样本?

setAttributes将重置HTML中的所有属性。 我写了一个扩展方法来避免这种情况:

 extension NSAttributedString { public convenience init?(HTMLString html: String, font: UIFont? = nil) throws { let options: [String: Any] = [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: NSNumber(value: String.Encoding.utf8.rawValue) ] guard let data = html.data(using: .utf8, allowLossyConversion: true) else { throw NSError(domain: "Parse Error", code: 0, userInfo: nil) } if let font = font { guard let attr = try? NSMutableAttributedString(data: data, options: options, documentAttributes: nil) else { throw NSError(domain: "Parse Error", code: 0, userInfo: nil) } var attrs = attr.attributes(at: 0, effectiveRange: nil) attrs[NSFontAttributeName] = font attr.setAttributes(attrs, range: NSRange(location: 0, length: attr.length)) self.init(attributedString: attr) } else { try? self.init(data: data, options: options, documentAttributes: nil) } } } 

testing样本:

 let html = "<html><body><h1 style=\"color:red;\">html text here</h1></body></html>" let font = UIFont.systemFont(ofSize: 16) var attr = try NSMutableAttributedString(HTMLString: html, font: nil) var attrs = attr?.attributes(at: 0, effectiveRange: nil) attrs?[NSFontAttributeName] as? UIFont // print: <UICTFont: 0x7ff19fd0a530> font-family: "TimesNewRomanPS-BoldMT"; font-weight: bold; font-style: normal; font-size: 24.00pt attr = try NSMutableAttributedString(HTMLString: html, font: font) attrs = attr?.attributes(at: 0, effectiveRange: nil) attrs?[NSFontAttributeName] as? UIFont // print: <UICTFont: 0x7f8c0cc04620> font-family: ".SFUIText"; font-weight: normal; font-style: normal; font-size: 16.00pt 

基本上你想要做的就是把NSAttributedString变成一个NSMutableAttributedString。

 let attributedT = // ... attributed string let mutableT = NSMutableAttributedString(attributedString:attributedT) 

现在,您可以调用addAttributes来在任何期望的范围内应用属性,如不同的字体,例如整个事物。

然而不幸的是,没有像斜体这样的象征特征的字体与具有该象征性特征的字体是不同的字体 。 因此,你将需要一个实用工具,从字体复制现有的符号特征,并将其应用到另一种字体:

 func applyTraitsFromFont(_ f1: UIFont, to f2: UIFont) -> UIFont? { let t = f1.fontDescriptor.symbolicTraits if let fd = f2.fontDescriptor.withSymbolicTraits(t) { return UIFont.init(descriptor: fd, size: 0) } return nil } 

好吧,那么,用这个工具武装起来,让我们试试看。 我将从一些简单的HTML开始,将其转换为一个属性string,就像你在做的一样:

 let html = "<p>Hello <i>world</i>, hello</p>" let data = html.data(using: .utf8)! let att = try! NSAttributedString.init( data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil) let matt = NSMutableAttributedString(attributedString:att) 

正如你所看到的,我已经转换为一个NSMutableAttributedString,正如我所build议的。 现在,我将循环通过字体的风格运行,更改为不同的字体,同时使用我的实用程序来应用现有的特征:

 matt.enumerateAttribute( NSFontAttributeName, in:NSMakeRange(0,matt.length), options:.longestEffectiveRangeNotRequired) { value, range, stop in let f1 = value as! UIFont let f2 = UIFont(name:"Georgia", size:20)! if let f3 = applyTraitsFromFont(f1, to:f2) { matt.addAttribute( NSFontAttributeName, value:f3, range:range) } } 

结果如下:

在这里输入图像说明

显然你可以调整这个过程,以便更复杂,取决于你的devise需求。

Swift 4解决scheme


  • 带便利初始值设定项的NSAttributedString扩展
  • 枚举属性string(HTML文档)的字体属性,并用提供的UIFontreplace
  • 保留原始的HTML字体大小,或从提供的UIFont使用font-size, UIFont useDocumentFontSize参数
  • 这种方法可以简单地将HTML转换为NSAttributedString,而不需要使用字体操作的重载,只需跳过字体参数@see guard语句

 extension NSAttributedString { convenience init(htmlString html: String, font: UIFont? = nil, useDocumentFontSize: Bool = true) throws { let options: [NSAttributedString.DocumentReadingOptionKey : Any] = [ .documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue ] let data = html.data(using: .utf8, allowLossyConversion: true) guard (data != nil), let fontFamily = font?.familyName, let attr = try? NSMutableAttributedString(data: data!, options: options, documentAttributes: nil) else { try self.init(data: data ?? Data(html.utf8), options: options, documentAttributes: nil) return } let fontSize: CGFloat? = useDocumentFontSize ? nil : font!.pointSize let range = NSRange(location: 0, length: attr.length) attr.enumerateAttribute(.font, in: range, options: .longestEffectiveRangeNotRequired) { attrib, range, _ in if let htmlFont = attrib as? UIFont { let traits = htmlFont.fontDescriptor.symbolicTraits var descrip = htmlFont.fontDescriptor.withFamily(fontFamily) if (traits.rawValue & UIFontDescriptorSymbolicTraits.traitBold.rawValue) != 0 { descrip = descrip.withSymbolicTraits(.traitBold)! } if (traits.rawValue & UIFontDescriptorSymbolicTraits.traitItalic.rawValue) != 0 { descrip = descrip.withSymbolicTraits(.traitItalic)! } attr.addAttribute(.font, value: UIFont(descriptor: descrip, size: fontSize ?? htmlFont.pointSize), range: range) } } self.init(attributedString: attr) } } 

用法1(replace字体)

 let attr = try? NSAttributedString(htmlString: "<strong>Hello</strong> World!", font: UIFont.systemFont(ofSize: 34, weight: .thin)) 

用法2( NSMutableAttributedString示例)

 let attr = try! NSMutableAttributedString(htmlString: "<strong>Hello</strong> World!", font: UIFont.systemFont(ofSize: 34, weight: .thin)) attr.append(NSAttributedString(string: " MINIMIZE", attributes: [.link: "@m"])) 

用法3(仅将HTML转换为NSAttributedString)

 let attr = try? NSAttributedString(htmlString: "<strong>Hello</strong> World!") 
 let font = UIFont(name: fontName, size: fontSize) textAttributes[NSFontAttributeName] = font self.attributedText = NSAttributedString(string: self.text, attributes: textAttributes)