UITextViewの文字を複数リンク化させる方法


# はじめに
![スクリーンショット 2020-05-21 19.19.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/74f0fdea-4314-cfaf-8c49-39a564021f4e.png)

iOSが意外に苦手なリンク化
HTMLみたいにタグで囲った範囲をリンク化する！みたいに出来たら便利なのですが、出来ないので

リンク化したい文字列の場所とタップした位置でゲームみたいに当たり判定でリンクをタップしたか判定します！

ViewController + Storyboardで解説


# Storyboard(Xibでも可)にUITextViewを貼り付ける
![スクリーンショット 2020-05-21 16.35.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/70628ff2-c9d3-6595-240b-4d01592824ca.png)

制約も適当に張ります。
![スクリーンショット 2020-05-21 16.35.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/5b33f9cd-88f6-6fd0-da7b-0b80eead9168.png)

UITextViewにTapGestureを張ります！
![スクリーンショット 2020-05-21 18.34.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/4033f9ef-4b5f-d55d-1ec5-3bf9e4f8cecf.png)

![スクリーンショット 2020-05-21 18.35.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/212a4fb3-bd9a-9066-90e8-b7a41a370000.png)

こんな感じ！

![スクリーンショット 2020-05-21 18.38.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/21b337c2-2161-ee12-42fb-2287579d3493.png)



## Storyboardとコードをつなげる
Controlキーを押しながら、TextViewをひっぱりコードに張りますー
（ちなみにエディタを分割して開くには、ファイルをoptionキーを押しながらクリックします)

![スクリーンショット 2020-05-21 16.38.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/d5a2966a-2be9-f610-f2fa-45975a69a07d.png)

TapGestureもコードにつなげておきます〜

![スクリーンショット 2020-05-21 18.43.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/cbd1ae4b-81d2-9809-e89d-fe04ea5b95d5.png)

以下のようになりました！

```swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var messageTextView: UITextView!
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }
    @IBAction func didTapMessageView(_ sender: UITapGestureRecognizer) {
    }
}
```

## 本題
messageTextViewの初期設定をしてあげます

仕様にもよりますが、以下の制御があったほうが理想だと思います。

```swift
messageTextView.isUserInteractionEnabled = true
messageTextView.isEditable = false
messageTextView.isSelectable = false
messageTextView.isScrollEnabled = false
```

```swift
   @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
        }
    }
```

次にタップ時の挙動を記述していきます。

```swift
    @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("縁側")
        }
    }
```

## 結果

![3j0z2-rnaio.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/07b79239-4381-95be-4e99-d824638e9b77.gif)

## 終わり
ポイントはNSLocationInRangeで毎回当たり判定的なものを行なって毎回処理を走らせるところです！

これをUIViewControllerRepresentableすればSwiftUIでも行けるのかも？
今度試してみます！