自定义安装的字体在UILabel中显示不正确

87

我正在尝试使用Adobe字体集专业版中获取的Helvetica Neue Condensed字体,但在UILabel中使用时似乎绘制不正确。

行高似乎被正确计算(我想是这样),但当字体显示时,它被对齐到边界框的顶部。我调用了[myLabel sizeToFit]并只调整了宽度以产生此屏幕截图:

不正确的字体渲染的屏幕截图

我在粗体和常规字体版本上都遇到了同样的问题。我能够从OSX上提取一个版本的Helvetica Neue Bold并将其放在我的设备上,显示很好(上图中的绿色背景)。

可能导致它以这种方式绘制的字体文件或我的代码存在什么问题?


我能否创建一个UIFont的子类来解决这些问题? - MikeQ
+1 - 我也遇到了同样的问题。我尝试使用 ZFont 来解决这个问题,它确实有所帮助,但还远远不够。可能是那些自定义字体在解释行距时出了什么问题(我真的不知道,但我必须认为这可能与此有关!)。 - Joe D'Andrea
你好!你最终找到解决方案了吗?如果是,请回答你的问题。提前感谢。 - Soonts
很不幸,我没有。而且我已经无法访问导致这个问题的原始字体文件了。我喜欢kolyuchiy的回答。。只是希望我能在我的特定情况下测试它。 - MikeQ
只是让你知道,这个问题已经在iOS7中得到了修复。 - The dude
13个回答

126
我在这里发布了一个解决方案,涉及到修补ttf字体文件:这里
以下是适用于我的自定义字体的解决方案,它在UILabel、UIButton等中出现了相同的问题。该字体的问题实际上是其上升高度属性与系统字体相比太小。上升高度是字体字符上方的垂直空白区域。要修复您的字体,您需要下载Apple Font Tool Suite命令行工具。然后,对您的字体执行以下操作:
~$ ftxdumperfuser -t hhea -A d Bold.ttf

这将创建Bold.hhea.xml文件。使用文本编辑器打开它并增加ascender属性的值。您需要进行一些实验,找出最适合您的确切值。在我的情况下,我将其从750更改为1200。然后再次运行以下命令行的实用程序,将您的更改合并回ttf文件中:
~$ ftxdumperfuser -t hhea -A f Bold.ttf

然后只需在您的应用程序中使用生成的ttf字体。

1
你也可以尝试使用Mensis或FontForge。这些应用程序也可以用于更改上升属性。 - kolyuchiy
1
你真是让我开心。这个问题困扰了我好几个星期了。我以后可以经常用到它! - Quxflux
1
请注意,通过增加上升高度,您将增加行间距 - 如果您的应用程序中有多行文本,则可能会出现问题。 - Pavel Alexeev
Joseph Lin的回答,在Glyphs上打开字体并重新保存,对iOS 6和iOS 7都适用。 - leolobato
2
请注意,为了确保在iOS 6和iOS 7上都能够良好对齐,您应该将升高线和行间距都调整为零! - Ken M. Haggerty
显示剩余5条评论

66

这是 kolyuchiy 答案的修改版。

我使用Glyphs打开我的字体,然后导出它而不做任何修改。不知何故,魔法般地,垂直对齐问题消失了!

更好的是,新字体与 sizeWithFont: 等方法相容,所以没有 Joshua 提到的问题。

我使用 kolyuchiy 提到的命令查看了 HHEA 表,发现 Glyphs 不仅修改了 ascender,还为我修改了 lineGapnumberOfHMetrics

以下是原始数据:

versionMajor="1"
versionMinor="0"
ascender="780"
descender="-220"
lineGap="200"
advanceWidthMax="1371"
minLeftSideBearing="-73"
minRightSideBearing="-52"
xMaxExtent="1343"
caretSlopeRise="1"
caretSlopeRun="0"
caretOffset="0"
metricDataFormat="0"
numberOfHMetrics="751"

之后:

versionMajor="1"
versionMinor="0"
ascender="980"
descender="-220"
lineGap="0"
advanceWidthMax="1371"
minLeftSideBearing="-73"
minRightSideBearing="-52"
xMaxExtent="1343"
caretSlopeRise="1"
caretSlopeRun="0"
caretOffset="0"
metricDataFormat="0"
numberOfHMetrics="748"
所以故事的寓意是-不要仅仅增加上升高度,还要修改其他相关值。
我并不是一个排版专家,所以我无法解释为什么和怎样做。如果有人能提供更好的解释,将不胜感激! :)

保存了使用Glyphs的TTF后,该字体在iOS 6和iOS 7上的表现几乎相同。先前它在iOS 6上的基线会对不齐。 - leolobato
7
感谢您最终搞清楚了这个问题!显然,iOS 6尊重lineGap属性,而iOS 7不予理会。解决方法是将lineGap设置为0,并使ascender相应增大。这正是Glyphs所做的,它在iOS 6和iOS 7上都有效。 - phatmann
是的。将lineGap减少到零(0),并保留ascender(在1991处)解决了我在Fedora免费的“Overpass”字体中遇到的问题。感谢大家对解决方案的指导。在iOS6和iOS7上都可以使用。 - stephenhouser
在尝试了多次Glyphs和OS X字体工具之后,我得出了与@phatmann相同的结论。问题是,最好使用OS X字体工具中的这个技巧,而不是仅仅使用Glyphs导出,因为Glyphs还会编辑字体的样式名称和PostScript名称,在某些情况下会导致xCode无法找到字体。 - huong

32
iOS 6 尊重字体的 lineGap 属性,而 iOS 7 忽略它。因此,只有 line gap 为 0 的自定义字体才能在两个操作系统上正常工作。
解决方案是将 lineGap 设为 0,并相应地增加 ascender。根据上面的answer,一个解决方案是从 Glyphs 导入和导出。但请注意,该应用程序的未来版本可能会修复这个“错误”。
一个更可靠的解决方案是按照post中的说明自己编辑字体。具体来说,
安装OS X字体工具。 将字体指标转储到文件中:ftxdumperfuser -t hhea -A d YOUR_FONT.ttf 在编辑器中打开转储文件。 通过将lineGap属性的值添加到ascender属性来编辑它。例如,如果lineGap为200且ascender为750,则使ascender为950。 将lineGap设置为0。 将更改合并到字体中:ftxdumperfuser -t hhea -A f YOUR_FONT.ttf 完成此操作后,您可能需要相应地调整UI。

6

对于运行OS X El Capitan的用户来说,你可能已经注意到苹果字体工具套件不再兼容(至少现在是这样)。

但是,您仍然可以使用免费的字体编辑软件FontForge执行由kolyuchiyJoseph Lin描述的更改。

使用FontForge打开字体,选择顶部菜单中的Element,然后转到Font Info> OS/2> Metrics。 在那里,您需要编辑HHEad Line Gap和HHead Ascent Offset值。

完成必要的编辑后,您只需在“文件”>“生成字体”中导出字体并选择正确的字体格式即可。


5
  1. 在这里下载并安装苹果的字体工具:https://developer.apple.com/downloads/index.action?q=font(下载链接在底部)
  2. 打开终端并cd到你的字体所在位置
  3. 运行此命令:ftxdumperfuser -t hhea -A d MY_FONT_NAME.ttf
  4. 现在你有一个带有一些字体属性的xml文件,请在文本编辑器中编辑它
  5. 搜索“lineGap”属性,并将其值加200
  6. 保存xml文件
  7. 运行此命令:ftxdumperfuser -t hhea -A f MY_FONT_NAME.ttf
  8. 删除xml文件
  9. 尝试在iOS 6上配置的字体,看看是否更好看。
  10. 如果需要,可以返回第3步并添加/减去“lineGap”属性。(我最终将我的配置增加了250)

4
我们在定制字体时也遇到了同样的问题。我们通过编辑字体上升高度属性来“修复”问题。然而,我们发现这会导致其他问题和布局问题。例如,使用我们编辑过的上升高度字体时,根据标签高度动态设置单元格高度时会变得混乱。
最终我们改变了UIButton的contentEdgeInsets属性。
yourButton.contentEdgeInsets = UIEdgeInsetsMake(-10, 0, 0, 0);

我不确定哪种方法更好,但我想分享另一种解决问题的方法。


2
同意。升高属性修复并不是理想的解决方案。 - Max MacLeod
1
嗨,约书亚,我刚刚发布了一个可能修复你提到的问题的方法。简而言之,除升高线外,还需要修改几个属性。 - Joseph Lin

3
感谢这个答案,我解决了我的字形问题,但是方法有些不同。
我用Glyphs(也适用于Glyphs mini)打开了我的字体,并在那里找到了这个部分(从Glyphs mini中获取,要到达那里,请按右上角的i按钮): enter image description here 只需删除所有这些对齐区域(或其中一些),它就会解决此问题。 对我来说完美地解决了问题。

2

从标签文本中创建带属性的文本对我有所帮助。这是一个扩展程序:

extension UILabel {
    /// You can call with or without param values; without will use default 2.0
    func setLineSpacing(lineSpacing: CGFloat = 2.0, lineHeightMultiple: CGFloat = 2.0) {
        guard let labelText = self.text else { return }
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = lineSpacing
        paragraphStyle.lineHeightMultiple = lineHeightMultiple
        let attributedString:NSMutableAttributedString
        if let labelattributedText = self.attributedText {
            attributedString = NSMutableAttributedString(attributedString: labelattributedText)
        } else {
            attributedString = NSMutableAttributedString(string: labelText)
        }
        // (Swift 4.2 and above) Line spacing attribute
        attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attributedString.length))
        self.attributedText = attributedString
    }
}

对于我的自定义字体,我从以下内容中得到了需要的结果:

self.myLabel.setLineSpacing(lineSpacing: 1.2, lineHeightMultiple: 1.2)

这可以通过使用原生提供的 NSMutableParagraphStyle() 实现,其中包含行高和间距属性(如果您不是使用编程方式添加标签,则在Storyboard中作为@IBOutlet属性可访问)。

1

1
你尝试过Core Text吗?我曾经通过Core Text成功地渲染了自定义字体,但我不知道它是否适合你的情况。

1
我可以确认核心文本没有这个问题。 - overboming

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接