LoginSignup
1
4

More than 5 years have passed since last update.

UITextViewで特定の文字の表示範囲を取得、ハイライト

Posted at

UITextView の中で、特定の文字が表示されている座標(CGRect)を下記メソッドで取得できます。
https://developer.apple.com/documentation/uikit/nslayoutmanager/1403255-boundingrect

func boundingRect(forGlyphRange glyphRange: NSRange, in container: NSTextContainer) -> CGRect

これで終わるのも何なんで、活用して「Qiita」を緑でハイライトする UITextView を用意してみました。

コード

class TextView: UITextView, UITextViewDelegate {

    // ~~ init() など省略 ~~
    // ~~ delegate に self を ~~

    private func set() {
        let range = (self.text as NSString).range(of: "Qiita")
        var rect = self.layoutManager.boundingRect(forGlyphRange: range, in: self.textContainer)
        rect.origin.x += self.textContainerInset.left
        rect.origin.y += self.textContainerInset.top

        self.viewWithTag(300)?.removeFromSuperview()

        let view = UIView()
        view.backgroundColor = .green
        view.frame = rect
        view.tag = 300
        self.addSubview(view)
        self.sendSubviewToBack(view)
    }

    func textViewDidChange(_ textView: UITextView) {
        set()
    }
}

解説

NSRange を取得

Swift.Range<String.Index> ではなく NSRange を取得したいので、 NSString にしてから操作します。

let range = (self.text as NSString).range(of: "Qiita")

文字列の座標 CGRect を取得

上記で得た NSRange の範囲の文字が、 textContainer 内のどこにあるかを取得します。

var rect = self.layoutManager.boundingRect(forGlyphRange: range, in: self.textContainer)

inset 分ずらす

UITextView には textContainerInset があり、この分ずれているので、その差分を足してあげます。

rect.origin.x += self.textContainerInset.left
rect.origin.y += self.textContainerInset.top

ハイライト UIView の追加

UIView のインスタンスを生成して載っけてますが、この処理は(上記コード内だと)文字を入力するたびに実行されるため、不要になった View も含めどんどん subView が増えていく形になります。
なので下記コードで以前に addSubview した UIView を消しておきます。

self.viewWithTag(300)?.removeFromSuperview()

その他

適当にちゃちゃっと書いたコードなので、色々工夫してみてください。

  • 上記コードで言う set() を呼ぶタイミング
  • 複数回「Qiita」の文字列が入力されても1つ目しかハイライトされない

環境

  • Swift: 5
1
4
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
1
4