LoginSignup
15
7

iOSのUILabelのサイズそのままでHiragino SansのqyjpやÉの上下が見切れないようにする

Last updated at Posted at 2018-12-09

課題

動作環境: iOS10〜12

UILabelのHiragino Sansを直接指定して【英語のみ】とかの場合、下記のようにqyjpやÉの上下が見切れたりします。

スクリーンショット 2018-12-03 18.42.45.png
label.font = UIFont(name: "HiraginoSans-W3", size: fontSize)!
label.text = "Font TestgpÉ"

【AutoLayoutやsizeThatFits()上のサイズを変更することなく】、描画領域を広げて下記みたいにしたい

スクリーンショット 2018-12-03 18.41.51.png

対応方法

上下にgutter(スペース)を確保して、描画領域を広げることで対応。
AutoLayout上のサイズを変更しないためにはalignmentRectInsetsを使用する

import UIKit

class VerticalGutterLabel: UILabel {

  /// フォントサイズの1/6のgutterを計算
  private var verticalGutter: CGFloat {
    guard let font = self.font else {
      return 4.0 //font未指定の時の値。だいたい4.0確保しておけばOKなのでそうしておく
    }
    return ceil(font.pointSize / 6.0)
  }

  /// サイズ(描画領域)を大きくする
  override var intrinsicContentSize: CGSize {
    if #available(iOS 17, *) {
      // iOS17以降だとalignmentRectInsetsが変わると自動的にintrinsicContentSizeも変わるようなので、iOS17以降はintrinsicContentSizeを大きくしない
      return super.intrinsicContentSize
    }
    var size = super.intrinsicContentSize
    size.height += verticalGutter * 2
    return size
  }

  /// 描画領域を大きくした分、描画位置を調整
  override func drawText(in rect: CGRect) {
    super.drawText(in: UIEdgeInsetsInsetRect(rect, UIEdgeInsets(top: verticalGutter,
                                                                left: 0.0,
                                                                bottom: verticalGutter,
                                                                right: 0.0)))
  }

  /// 描画領域を大きくした分の部分をAutoLayout上で加算されないように相殺する処理
  override var alignmentRectInsets: UIEdgeInsets {
    let alignmentRectInsets = super.alignmentRectInsets
    return UIEdgeInsets(top: alignmentRectInsets.top + verticalGutter,
                        left: alignmentRectInsets.left,
                        bottom: alignmentRectInsets.bottom + verticalGutter,
                        right: alignmentRectInsets.right)
  }

  /// alignmentRectInsetsの影響でsizeThatFits(sizeToFit含む)が小さくなってしまうのを相殺する処理
  override func sizeThatFits(_ size: CGSize) -> CGSize {
    var size = super.sizeThatFits(size)
    size.height += verticalGutter * 2
    return size
  }
}

修正内容の説明はVerticalGutterLabelのコメント参照

参考にした情報
https://stackoverflow.com/questions/20985085/uilabel-clipping-italic-oblique-text-at-left-and-right-edges-of-content-ios

対応時の注意!!

描画領域を広げているのでbackgroundColorなどの描画領域も広がっているので注意!!

スクリーンショット 2018-12-03 15.52.09.png

"HiraginoSans"で直接指定する理由

Zeplinというツールをデザイン指示に使用しているのですが、
Zeplinで指定するフォントサイズをそのまま設定しても
システムフォント(systemFont(ofSize:)boldSystemFont(ofSize:))だと小さくなってしまうという問題があったためです。

Zeplinでのフォントサイズと"HiraginoSans"直接指定の時のフォントサイズが一致していたため"HiraginoSans"直接指定しています。

よくわかっていないですが、システムフォント指定の場合は"HiraginoSans"の本来のフォントサイズより小さく表示しているのかな。。と思っています。

次の記事は

明日、食べログAdventCalendar11日目は @itume さんからの「POROと大人になった僕」です。

15
7
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
7