iOS 上利用 fallback 机制为不一样语言的文字 (script) 设定字体,从而使得文本混排更为优雅

若是您是一位 WEB 开发者,相信您对 CSS 的 font-family 属性必定不会陌生。一般咱们会为 font-family 属性设置一长串的字体(家族)列表,就像这样的:css

.text { font-family: Menlo, Monaco, Consolas, "Courier New", monospace, Arial, "Microsoft YaHei", "黑体", "宋体", sans-serif; }
复制代码

有人确定会问,为何要这么设置啊?若是你足够细心,你必定会发现当你浏览该网页时英文字体和中文字体并非同一种字体,若是你在不一样的操做系统甚至不一样的电脑上看到网页所呈现的字体也不同。这又是为何呢?git

此外,在您使用 Microsoft Word 进行段落排版的时候,你会发现 Word 能够自动对中文样式应用中文字体,对英文样式应用英文字体。这又是如何作到的呢?github

在实际的排版需求中,为了好看,咱们一般会须要针对不一样语言的文字 (script) 进行不一样的字体设定,以达到最佳的视觉效果。固然,对于咱们来讲,最多见的仍是中英文混排。一般设计人员给出的设计稿很是漂亮,但是中英文使用了不一样的字体,咱们开发人员该如何高保真地还原设计稿的原始设计呢?swift

很显然,对于 WEB 开发者来讲,已经有了很好的解决方案,而对于其余客户端的同窗来讲,这估计应该就有点犯难了,咱们一般会告诉设计人员:“系统不支持” 抑或 “作不了” 之类的话。那事实上,到底能不能作到呢?答案是确定的。app

要实现这个,咱们先来了解一个概念:fallback 机制。字体

这种机制一般是首先规定拉丁字母、西里尔字母、希腊字母等西文的字体,而后以必定的顺序分别规定阿拉伯字母、天城文(例如印度文)、日文、韩文、简体中文、繁体中文等文字的字体。文本引擎会尽可能用优先的字体来显示当前遇到的字符,若是 fallback 列表中最靠前的字体不支持此字符,就向后找(这就是所谓 fallback)。CSS 的 font-family 属性基本也是这样工做的。动画

Windows 其实也是相似这样的。目前 Windows 7 的西文字体是 Segoe UI,简体中文字体是微软雅黑,繁体中文字体是微软正黑,日文字体是 Meiryo,天城文字体是 Mangal…… 因此你根本不须要这样的软件,你的操做系统已是这样了。ui

由于中日韩汉字共享 Unicode code point,因此当一个字(好比「直」这个字)同时受到简体中文、繁体中文、日文、韩文字体的支持,操做系统会根据当前的 locale 以及系统语言列表的顺序选择最优先的书写系统的字体。spa

然而,不多谈及移动操做系统上的字体 fallback 机制,更别说实现了,还好我通过不断查找,找到一些蛛丝马迹。因为本人是一名 iOS 开发者,因此咱们以 iOS 为例,来看看它的实现方式。操作系统

一般,咱们使用以下的方式建立一个字体:

let systemFont = UIFont.systemFont(ofSize: fontSize)
复制代码

显然,若是您还这样建立,确定没法实现咱们的目标。那应该怎么作呢?咱们须要使用到 UIFontDescriptor,代码以下:

public extension UIFont {
    convenience init(names: [String], size: CGFloat) {
        
        if names.first != nil {
            let mainFontName = names.first!
            
            let descriptors = names.map { UIFontDescriptor(fontAttributes: [.name: $0]) }
            
            let attributes: [UIFontDescriptor.AttributeName: Any] = [
                UIFontDescriptor.AttributeName.cascadeList: descriptors,
                UIFontDescriptor.AttributeName.name: mainFontName,
                UIFontDescriptor.AttributeName.size: size,
                ]
            
            let customFontDescriptor: UIFontDescriptor = UIFontDescriptor(fontAttributes: attributes)
            self.init(descriptor: customFontDescriptor, size: size)
        }
        else{
            let systemFont = UIFont.systemFont(ofSize: size)
            let systemFontDescriptor: UIFontDescriptor = systemFont.fontDescriptor
            self.init(descriptor: systemFontDescriptor, size: size)
        }
    }
    
    convenience init(families: [String], size: CGFloat, weight: UIFont.Weight = .regular) {
        
        if families.first != nil {
            let mainFontFamily = families.first!
            let descriptors = families.map { UIFontDescriptor(fontAttributes: [.family: $0]) }
            let traits = [UIFontDescriptor.TraitKey.weight: weight]
            
            let attributes: [UIFontDescriptor.AttributeName: Any] = [
                UIFontDescriptor.AttributeName.cascadeList: descriptors,
                UIFontDescriptor.AttributeName.family: mainFontFamily,
                UIFontDescriptor.AttributeName.size: size,
                UIFontDescriptor.AttributeName.traits: traits
            ]
            
            let customFontDescriptor: UIFontDescriptor = UIFontDescriptor(fontAttributes: attributes)
            self.init(descriptor: customFontDescriptor, size: size)
        }
        else{
            let systemFont = UIFont.systemFont(ofSize: size, weight: weight)
            let systemFontDescriptor: UIFontDescriptor = systemFont.fontDescriptor
            self.init(descriptor: systemFontDescriptor, size: size)
        }
    }
}
复制代码

调用示例:

let text = "これは日本語文章と Roman Text の混植文章です。美しいヒラギノと San Francisco で日本語とローマ字を書きます。System Font のフォントメトリクスには独自の調整が入っています。\n\nあのイーハトーヴォの\nすきとおった風、\n夏でも底に冷たさをもつ青いそら、\nうつくしい森で飾られたモーリオ市、\n郊外のぎらぎらひかる草の波。\n祇辻飴葛蛸鯖鰯噌庖箸\n底辺直卿蝕薩化\nABCDEFGHIJKLM\nabcdefghijklm\n1234567890iClockᴹᴵᴺᴵClockªMINI"
let font = UIFont(families: ["Lucida Grande", "Baskerville", "Apple SD Gothic Neo"], size: 20, weight: .medium)
//let font = UIFont(names: ["LucidaGrande", "Baskerville", "AppleSDGothicNeo-Thin"], size: 20)
label.font = font
label.text = text
复制代码

其中 family 和 font name 这两个别搞混了,不知道怎么在 iOS 上看字体的 family 和 font name 的能够下载这个 App:字体预览(itunes.apple.com/cn/app/字体预览…)

若是是自定义字体,也能够在同一个wifi的局域网中将字体上传到 App 里查看。

演示动画:

Github源码: github.com/pcjbird/fbC…

参考连接:

是否有一种软件可以对不一样语言的文字指定不一样的字体?

www.zhihu.com/question/20…

Fallback to pure Japanese font. No more Chinese font in Japanese text on iOS apps.

github.com/usagimaru/F…

相关文章
相关标签/搜索