字体与文本高度计算

2019-02-22  本文已影响0人  lsh_01

字体

在 iOS 9 中,新增了两个字体家族San Francisco(英文)PingFangSC(简体中文)
其中 San Francisco 分为.SFUIText.SFUIDisplay两种字体;PingFangSC 分为PingFangSC-RegularPingFangSC-LightPingFangSC-Medium三种字体。

在 iOS 9 之前,常用英文字体家族为Helvetica NeueHelvetica;常用简体中文字体为STHeitiSC
其中 STHeitiSC 分为STHeitiSC-LightSTHeitiSC-Medium两种字体;STHeitiSC 字体家族在 iOS 9 中已被移除。

这四种字体的基本属性如下:(表格中的值均为系数,乘以字号可以得到真实的值)

属性 .SFUIText / .SFUIDisplay Helvetica Neue / Helvetica PingFangSC STHeitiSC-Light / STHeitiSC-Medium
ascender 0.952148 0.952000 / 0.920020 1.060000 0.860000
capheight 0.704590 0.714000 / 0.717285 0.860000 0.778000 / 0.718000
xheight 0.526367 / 0.507812 0.517000 / 0.522949 0.600000 0.591000 / 0.531000
base-line 0 0 0 0
descender -0.241211 -0.213000 / -0.229980 -0.340000 -0.140000
lineheight 1.193359 1.165000 / 1.150000 1.400000 1.000000
leading 0 0.028000 / 0 0 1.000000(0.03)

.SFUIText 与 .SFUIDisplay 的差异主要是字体间距的不同,Text 字体间距较大,使得在小的字体中更加易读。
在APP里面使用了 SF 字体后,由操作系统自动选择使用 .SFUIText 还是 .SFUIDisplay。当字号小于20号时,选择 .SFUIText,否则选择 .SFUIDisplay。

文本高度计算

规则如下:

  1. 文本为空时,高度为字体的 lineHeight。
  2. 只有一行时,高度为字体的 lineHeight + leading。
  3. 如果 leading=0 且 lineSpacing>0,高度为 lineHeight * numOfLines + lineSpacing * (numOfLines - 1)。
  4. 如果 leading=0 且 lineSpacing<=0,高度为 lineHeight * numOfLines。
  5. 如果 leading>0 且 lineSpacing<-leading,高度为 lineHeight * numOfLines。
  6. 如果 leading>0 且 lineSpacing<0 且 lineSpacing>=-leading,高度为 lineHeight * numOfLines + (lineSpacing + leading) * (numOfLines - 1)。
  7. 如果 leading>0 且 lineSpacing>=0 且 lineSpacing<=leading,高度为 lineHeight * numOfLines + leading * (numOfLines - 1)。
  8. 如果 leading>0 且 lineSpacing>leading,高度为 lineHeight * numOfLines + lineHeight * (numOfLines - 1)。

代码:

func textHeight(numOfLines: Int, lineHeight: CGFloat, leading: CGFloat, lineSpacing: CGFloat) -> CGFloat {
    if numOfLines == 0 {
        return lineHeight
    }
    else if numOfLines == 1 {
        return lineHeight + leading
    }
    
    if leading == 0 {
        if linespacing > 0 {
            return lineHeight * CGFloat(numOfLines) + linespacing * CGFloat(numOfLines - 1)
        } else {
            return lineHeight * CGFloat(numOfLines)
        }
    }
    else if leading > 0 {
        if linespacing < -leading {
            return lineHeight * CGFloat(numOfLines)
        }
        else if linespacing < 0 {
            return lineHeight * CGFloat(numOfLines) + (linespacing + leading) * CGFloat(numOfLines - 1)
        }
        else if linespacing <= leading {
            return lineHeight * CGFloat(numOfLines) + leading * CGFloat(numOfLines - 1)
        }
        else {
            return lineHeight * CGFloat(numOfLines) + linespacing * CGFloat(numOfLines - 1)
        }
    }
    else {
        fatalError("leading of font < 0")
    }
}

其他需要注意的事项:

  1. 计算文本高度时,必须包含 NSStringDrawingUsesLineFragmentOrigin 参数,否则只能是单行。
  2. 计算文本高度时,如果不包含 NSStringDrawingUsesFontLeading 参数,leading 为 0;否则取字体的 leading。
  3. Heiti SC 的 leading 值为 1.00,但参与计算的值是 0.03。
  4. iOS 9 开始 Heiti SC 会被强制替换为 PingFangSC。
  5. 由于 Heiti SC 的 lineHeight=1,而 PingFangSC 的 lineHeight=1.4,iOS 9 前后的汉字行间距存在差异。
  6. iOS 9 开始默认英文字体为 SF 系列,原有的 Helvetica 系列仍然可以使用。
  7. San Francisco 系列中的 SF 用在 OS X 和 iOS 中,SF Compact 用在 Watch OS 中。
上一篇下一篇

猜你喜欢

热点阅读