はじめに
iOSが意外に苦手なリンク化
HTMLみたいにタグで囲った範囲をリンク化する!みたいに出来たら便利なのですが、出来ないので
リンク化したい文字列の場所とタップした位置でゲームみたいに当たり判定でリンクをタップしたか判定します!
ViewController + Storyboardで解説
Storyboard(Xibでも可)にUITextViewを貼り付ける
こんな感じ!
Storyboardとコードをつなげる
Controlキーを押しながら、TextViewをひっぱりコードに張りますー
(ちなみにエディタを分割して開くには、ファイルをoptionキーを押しながらクリックします)
TapGestureもコードにつなげておきます〜
以下のようになりました!
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var messageTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func didTapMessageView(_ sender: UITapGestureRecognizer) {
}
}
本題
messageTextViewの初期設定をしてあげます
仕様にもよりますが、以下の制御があったほうが理想だと思います。
messageTextView.isUserInteractionEnabled = true
messageTextView.isEditable = false
messageTextView.isSelectable = false
messageTextView.isScrollEnabled = false
@IBOutlet weak var messageTextView: UITextView! {
didSet {
messageTextView.isUserInteractionEnabled = true
messageTextView.isEditable = false
messageTextView.isSelectable = false
messageTextView.isScrollEnabled = false
let mutableAttributedString = NSMutableAttributedString()
let normalAttributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor.gray,
.font: UIFont.monospacedSystemFont(ofSize: 18, weight: .medium)
]
let linkAttributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor.link,
.underlineStyle: NSUnderlineStyle.single.rawValue,
.font: UIFont.monospacedSystemFont(ofSize: 22, weight: .medium)
]
mutableAttributedString.append(
NSAttributedString(
string: "吾輩わがはいは猫である。",
attributes: normalAttributes
)
)
mutableAttributedString.append(
NSAttributedString(
string: "名前",
attributes: linkAttributes
)
)
mutableAttributedString.append(
NSAttributedString(
string: "はまだ無い。",
attributes: normalAttributes
)
)
mutableAttributedString.append(
NSAttributedString(
string: "どこで",
attributes: linkAttributes
)
)
mutableAttributedString.append(
NSAttributedString(
string: "生れたかとんと見当けんとうがつかぬ。",
attributes: normalAttributes
)
)
messageTextView.attributedText = mutableAttributedString
}
}
次にタップ時の挙動を記述していきます。
@IBAction func didTapMessageView(_ sender: UITapGestureRecognizer) {
guard let text = messageTextView.text else { return }
let name = "名前"
let pos = "どこで"
let nameRange = (text as NSString).range(of: name)
let posRange = (text as NSString).range(of: pos)
let location = sender.location(in: messageTextView)
let textPosition = messageTextView.closestPosition(to: location)
let tapPosition = messageTextView.offset(from: messageTextView.beginningOfDocument, to: textPosition!)
if NSLocationInRange(tapPosition, nameRange) {
print("たま")
}
if NSLocationInRange(tapPosition, posRange) {
print("縁側")
}
}
結果
終わり
ポイントはNSLocationInRangeで毎回当たり判定的なものを行なって毎回処理を走らせるところです!
これをUIViewControllerRepresentableすればSwiftUIでも行けるのかも?
今度試してみます!