意外と見つからなくて困ったので、自分なりの実装方法を共有します。
コード
extension UILabel {
var isOverflowing:Bool {
return (realLineCount() > self.numberOfLines)
}
private func realLineCount()-> Int {
guard let font = self.font else { return 0 }
guard let text = self.text, text != "" else { return 0 }
let sizeForWidthCheck = CGSize(width: Int.max, height: Int(ceil(font.pointSize)))
let oneLineWidth = text.boundingRect(with: sizeForWidthCheck,
options: .usesLineFragmentOrigin,
attributes: [NSAttributedString.Key.font: font],
context: nil).width
let boundingWidth = text.boundingRect(with: self.bounds.size,
options: .usesLineFragmentOrigin,
attributes: [NSAttributedString.Key.font: font],
context: nil).width
return Int(ceil(oneLineWidth / boundingWidth))
}
}
解説
UILabel.textは省略されている場合でも全文を返してくれるので、それを使用します。
realLineCount
メソッドで、省略せずに全文を描画したときの行数を計算します。
let oneLineWidth = text.boundingRect(with: sizeForWidthCheck,
options: .usesLineFragmentOrigin,
attributes: [NSAttributedString.Key.font: font],
context: nil).width
boundingRectメソッドはStringを描画した場合のRectを返してくれます。
これを使って、1行で全部描画したときの横幅を計算します。1
return Int(ceil(oneLineWidth / boundingWidth))
それをboundingWidth
(Labelに描画したときの横幅)で割って、行数を計算します。2
小数点以下はいらないので、繰り上げます。
var isOverflowing:Bool {
return (realLineCount() > self.numberOfLines)
}
計算した行数を自身の行数(ここは実際に表示される行数)と比較し、
大きければ省略されているのでtrue
を返します。
純正で用意して欲しいな……
ありがとうございました。