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