UITextViewでリンクを挿入して色を変更したい



これは[SOUSEI Technology アドベントカレンダー2日目](https://qiita.com/advent-calendar/2020/st)の記事です！
普段はiOS開発をメインに活動しています。そこからのミニTIPSを投稿していきます💪

## UITextViewでリンクを挿入する

UITextViewのattributedTextプロパティを使用してリンクを挿入することができます。

```swift
guard let url = URL(string: "http://qiita.com") else { return }

let attributes: [NSAttributedString.Key: Any] = [
    .link: url
]
        
let attributedString = NSMutableAttributedString()
attributedString.append(NSAttributedString(string: "Qiita", attributes: attributes))
attributedString.append(NSAttributedString(string: "アドベントカレンダー2020"))
        
textView.attributedText = attributedString
```

こちらを実装するとこのような見た目になります。
![Simulator Screen Shot - iPhone 11 Pro - 2020-12-01 at 19.41.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596715/292b0108-6722-5420-848a-74525c9717c5.png)

ご覧のように勝手にリンク色（この記事ではこの色をリンク色と定義します）に変更してくれます。

## リンク色を変える
ここから本題ですが、要件によってはリンク色を変えたいというようなこともあると思います。
その時はUITextViewのlinkTextAttributesプロパティを使用することで実現できます。

```swift
guard let url = URL(string: "http://qiita.com") else { return }

// リンク色を変更
let linkAttributes: [NSAttributedString.Key: Any] = [
    .foregroundColor: UIColor.red
]
textView.linkTextAttributes = linkAttributes
        
let attributes: [NSAttributedString.Key: Any] = [
    .link: url
]
        
let attributedString = NSMutableAttributedString()
attributedString.append(NSAttributedString(string: "Qiita", attributes: attributes))
attributedString.append(NSAttributedString(string: "アドベントカレンダー2020"))
        
textView.attributedText = attributedString
```

![Simulator Screen Shot - iPhone 11 Pro - 2020-12-01 at 19.42.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596715/e992a093-53eb-5180-2e74-24d640b3bfba.png)

このようにバッチリとリンク色が変わってくれました。
色を変更したい場合は、.foregroundColorで好きな色を指定してください。

## ついでに下線も付けたい
ここからはおまけです。
リンクっぽく下線を付けてみましょう。
linkAttributesに下線の項目を付け足せばOKです。

```swift
let linkAttributes: [NSAttributedString.Key: Any] = [
    .foregroundColor: UIColor.red,
    .underlineColor: UIColor.red,                     // 下線の色
    .underlineStyle: NSUnderlineStyle.single.rawValue // 下線のスタイル
]
textView.linkTextAttributes = linkAttributes
        
let attributes: [NSAttributedString.Key: Any] = [
    .link: url
]
        
let attributedString = NSMutableAttributedString()
attributedString.append(NSAttributedString(string: "Qiita", attributes: attributes))
attributedString.append(NSAttributedString(string: "アドベントカレンダー2020"))
        
textView.attributedText = attributedString
```

![Simulator Screen Shot - iPhone 11 Pro - 2020-12-01 at 19.57.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596715/d9718ab4-383e-f58b-5940-b6ff796639ff.png)


下線の色は.underlineColorで好きな色を指定してください。
下線のスタイルもsingle以外にたくさんあるので公式ドキュメントを参考に試してみると良いと思います。
[NSUnderlinestyleについて](https://developer.apple.com/documentation/uikit/nsunderlinestyle)

## foregroundColorの注意点
linkAttributesではなく、attributedTextでforegroundColorを指定してもリンク色は変わってくれません。`.link`を指定したら該当の箇所はリンク色になり、好きな色に変化してくれません。

```swift
let attributes: [NSAttributedString.Key: Any] = [
    .link: url,
    .foregroundColor: UIColor.red // .linkがあるとこの指定は無効
]
```

## リンクをタップして外部ブラウザ以外で遷移させたい
こちらもおまけですが、UITextViewをタップした時にはこれまで書いた実装をすると、外部ブラウザでリンクが開きます。
しかし、アプリによってはWebViewやSafariViewControllerで開かせたいということもあると思います。
その場合はUITextViewDelegateを使用しましょう。
今回はSafariViewControllerで開くパターンを例とします。

```swift
import UIKit
import SafariServices

class ViewController: UIViewController {

    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

        textView.delegate = self
    }
}

extension ViewController: UITextViewDelegate {

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        let safariViewController = SFSafariViewController(url: URL)
        present(safariViewController, animated: true, completion: nil)
        return false
    }

}

```

こちらでSafariViewControllerで開くことができると思います。
`return false`にしているところがポイントで、`return true`にすると外部ブラウザが開きます。
この例で`true`にするとアプリ内ではSafariViewControllerが開き、外部ブラウザでも同じページが二重で開きます。
注意してください。