You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UIKit解码HTML为富文本时字体变为Times New Roman的技术求助

解决UIKit中HTML转NSAttributedString时字体变为Times New Roman并保留样式的问题

我开发了一个基于UIKit的文本编辑器,将内容保存为HTML格式(示例如下),但使用NSAttributedString的HTML解码功能时,所有字体都会被自动替换为Times New Roman,无法保留原有的Apple系统字体、加粗、斜体及字号样式。

示例HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Content-Style-Type" content="text/css">
<title></title>
<meta name="Generator" content="Cocoa HTML Writer">
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 24.0px '.AppleSystemUIFont'; color: #454545}
p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 17.0px '.AppleSystemUIFont'; color: #454545}
span.s1 {font-family: '.SFUI-Bold'; font-weight: bold; font-style: normal; font-size: 24.00px}
span.s2 {font-family: '.SFUI-RegularItalic'; font-weight: normal; font-style: italic; font-size: 17.00px}
</style>
</head>
<body>
<p class="p1"><span class="s1">Test</span></p>
<p class="p2"><span class="s2">Test</span></p>
</body>
</html>

原解码代码

extension String {
    var htmlToAttributedString: NSAttributedString? {
        guard let data = data(using: .utf8) else { return nil }
        do {
            return try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding:String.Encoding.utf8.rawValue], documentAttributes: nil)
        } catch {
            return nil
        }
    }
    var htmlToString: String {
        return htmlToAttributedString?.string ?? ""
    }
}

方案1:修改HTML的CSS字体名称(源头解决)

问题根源在于HTML中使用了.AppleSystemUIFont、.SFUI-Bold这类私有字体名称,WebKit的HTML解码器无法正确识别,从而 fallback到Times New Roman。将CSS中的字体名替换为标准的系统字体别名-apple-system,解码器就能正确映射到Apple系统字体,同时保留所有样式。

修改后的示例HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Content-Style-Type" content="text/css">
<title></title>
<meta name="Generator" content="Cocoa HTML Writer">
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 24.0px -apple-system; color: #454545; font-weight: bold;}
p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 17.0px -apple-system; color: #454545; font-style: italic;}
span.s1 {font-family: -apple-system; font-weight: bold; font-style: normal; font-size: 24.00px}
span.s2 {font-family: -apple-system; font-weight: normal; font-style: italic; font-size: 17.00px}
</style>
</head>
<body>
<p class="p1"><span class="s1">Test</span></p>
<p class="p2"><span class="s2">Test</span></p>
</body>
</html>

方案2:解码后替换字体并保留原有样式(兼容已保存内容)

如果无法修改已保存的HTML内容,可以在解码完成后,遍历NSAttributedString的属性,将Times New Roman替换为对应的系统字体,同时保留原字号、加粗、斜体等样式:

扩展方法实现

extension NSAttributedString {
    func withSystemFontsPreservingStyles() -> NSAttributedString {
        let mutableString = NSMutableAttributedString(attributedString: self)
        
        mutableString.enumerateAttribute(.font, in: NSRange(location: 0, length: mutableString.length)) { (value, range, _) in
            guard let originalFont = value as? UIFont else { return }
            
            // 根据原字体的样式生成对应的系统字体
            var targetFont: UIFont
            let traits = originalFont.fontDescriptor.symbolicTraits
            
            switch (traits.contains(.traitBold), traits.contains(.traitItalic)) {
            case (true, true):
                targetFont = UIFont.systemFont(ofSize: originalFont.pointSize, weight: .bold).italicized()
            case (true, false):
                targetFont = UIFont.boldSystemFont(ofSize: originalFont.pointSize)
            case (false, true):
                targetFont = UIFont.italicSystemFont(ofSize: originalFont.pointSize)
            default:
                targetFont = UIFont.systemFont(ofSize: originalFont.pointSize)
            }
            
            mutableString.addAttribute(.font, value: targetFont, range: range)
        }
        
        return mutableString
    }
}

使用方式

if let htmlAttributedString = yourHtmlString.htmlToAttributedString {
    let styledString = htmlAttributedString.withSystemFontsPreservingStyles()
    // 将styledString赋值给UILabel或UITextView等控件
}

方案对比

  • 方案1:从根源解决问题,解码过程直接生成正确的系统字体,性能更优,适合新保存的内容。
  • 方案2:无需修改现有HTML,兼容历史数据,但需要额外遍历处理属性,性能略低。

内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 18:32:11