12
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Tips] UITextViewの行数などを取得する

Last updated at Posted at 2019-03-05
スクリーンショット 2019-03-05 16.34.16.png

概要

UITextviewの表示状況取得のためのTips。ちなみに設定系は、[Tips] UITextviewをUILabelっぽく使うで。

0,取得タイミングについて

同じtextでも表示領域がちがえば行数も変わってくるわけで、例えば表示前に情報を取得しようと思ってもうまくいかないことが多い。AutoLayoutがベースになっているなら、UIViewControllerライフサイクルのviewWillLayoutSubViewsタイミングで取得するのをオススメ。

1,行数を取得する

UITextViewの行数を取得する
extension UITextView {
    var numberOfLines: Int {
        // prepare
        var computingLineIndex = 0
        var computingGlyphIndex = 0
        // compute
        while computingGlyphIndex < layoutManager.numberOfGlyphs {
            var lineRange = NSRange()
            layoutManager.lineFragmentRect(forGlyphAt: computingGlyphIndex, effectiveRange: &lineRange)
            computingGlyphIndex = NSMaxRange(lineRange)
            computingLineIndex += 1
        }
        // return
        if textContainer.maximumNumberOfLines > 0 {
            return min(textContainer.maximumNumberOfLines, computingLineIndex)
        } else {
            return computingLineIndex
        }
    }
}

Apple公式ドキュメントに方法(Objective-C!!!)がでていたのでこれを参考に実装。ただし、素直に実装してみると、「最大行数設定しているのに改行の入り方によってはそれよりも大きい数が返ってきてしまう」という不具合があったため、上記のように返り値に少し工夫をした。

参考:Apple: Text Layout Programming Guide: Counting Lines of Text

2,表示省略されているかを取得する

UITextViewの表示省略されているか
extension UITextView {
    var isTruncated: Bool {
        // prepare
        let lineMax = textContainer.maximumNumberOfLines > 0 ? textContainer.maximumNumberOfLines : Int.max
        var computingLineIndex = 0
        var computingGlyphIndex = 0
        // compute & return
        while computingGlyphIndex < layoutManager.numberOfGlyphs {
            // analyze line
            let overLineMax = computingLineIndex > lineMax
            let existsTruncatedGlyph: Bool = {
                let truncatedGlyphRange = layoutManager.truncatedGlyphRange(inLineFragmentForGlyphAt: computingGlyphIndex)
                return truncatedGlyphRange.location != NSNotFound
            }()
            // guard
            guard !overLineMax, !existsTruncatedGlyph else {
                return true
            }
            // prepare for next
            var lineRange = NSRange()
            self.layoutManager.lineFragmentRect(forGlyphAt: computingGlyphIndex, effectiveRange: &lineRange)
            computingGlyphIndex = NSMaxRange(lineRange)
            computingLineIndex += 1
        }
        return false
    }
}

1の応用。指定行の省略文字位置を取得するファンクションtruncatedGlyphRange(inLineFragmentForGlyphAt:)がlayoutManagerにあるためこれを用いる。

ちなみに、設定系の話だが、.textContainer.lineBreakMode = .byTruncatingTailとかの設定をしないと3点リーダー等の省略文字は出ない。

備考

(特になし)

12
10
0

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
12
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?