Swift で UITextView の URL リンクを短縮表示させる。

# ０．はじめに

Swift で UITextView に表示される URL リンクを短縮表示させたかったので、やってみました。

ついでに、キーワード検索時の強調表示もできる様にしてます。

以下の記事を参考にさせて頂きました。

* [UITextViewにタップ可能なリンクを挿入する \- Qiita](https://qiita.com/shtnkgm/items/3c8b6b794219fbf087ba)
* [UITextViewで複雑なHighlightを表現する \- Qiita](https://qiita.com/rinov/items/da450d0ba9dffaaf8967)

感謝 ♪♪♪

🙇‍♂️🙇‍♂️🙇‍♂️

# １．コード

今回は、UITextView の Extension として、`setAttributedText` という関数を追加しました。

パラメータの説明は、以下。

* `text: String` : [元となるテキスト文字列]
* `shortUrlMaxNum: Int = Int()` : [短縮されるURLの最大文字数]
* `keyword: String? = nil` : [検索キーワード]
* `keywordBackgroundColor: UIColor = .yellow` : [検索キーワードの強調される背景色]

```swift:UITextView+Extension.swift
//
//  UITextView+Extension.swift
//

import UIKit

extension UITextView {
    func setAttributedText(text: String, shortUrlMaxNum: Int = Int(), keyword: String? = nil, keywordBackgroundColor: UIColor = .yellow) -> Int {
        var tempText: String = text
        var links: [(url: URL, range: NSRange)] = []
        if shortUrlMaxNum > 0 {
            if let _detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) {
                var truncateCount: Int = 0
                for link in _detector.matches(in: tempText, range: NSMakeRange(0, tempText.utf16.count)) {
                    let startIndex = tempText.utf16.index(tempText.startIndex, offsetBy: (link.range.location - truncateCount))
                    let endIndex = tempText.utf16.index(startIndex, offsetBy: link.range.length)
                    let _tempText = tempText[startIndex..<endIndex]
                    if let _url = link.url, let _ = _url.host, _tempText == _url.absoluteString {
                        var range: NSRange = link.range
                        if _url.absoluteString.count > shortUrlMaxNum {
                            let replacementString: String = _url.absoluteString.prefix(shortUrlMaxNum) + "..."
                            range = NSMakeRange(link.range.location - truncateCount, replacementString.count)
                            tempText.replaceSubrange(
                                Range<String.Index>(NSMakeRange(range.location, link.range.length), in: tempText)!,
                                with: replacementString)
                            truncateCount += (link.range.length - replacementString.count)
                        } else {
                            range = NSMakeRange(link.range.location - truncateCount, _url.absoluteString.count)
                        }
                        links.append((url: _url, range: range))
                    }
                }
            }
        }
        let attrText: NSMutableAttributedString = NSMutableAttributedString(string: tempText, attributes: [
            .font : self.font as Any,
            .foregroundColor : self.textColor as Any,
        ])
        for link in links {
            attrText.addAttribute(.link, value: link.url.absoluteString, range: link.range)
        }
        if let _keyword = keyword {
            if let _regex = try? NSRegularExpression(pattern: _keyword) {
                for match in _regex.matches(in: tempText, range: NSMakeRange(0, tempText.count)) as [NSTextCheckingResult] {
                    attrText.addAttribute(.backgroundColor, value: keywordBackgroundColor, range: match.range)
                }
            }
        }
        self.attributedText = attrText
        return self.attributedText.string.count
    }
}
```

<br>

で、こんな感じに表示されます。

![IMG_0152.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161939/a03779df-2440-b67e-469a-eb6c98df97f5.png)

<br>

# ９９．ハマりポイント

* 短縮URL後のテキスト文字列の編集が、結構面倒臭かったですね…。バグってないかちょっと心配…。

* あと、`tempText.utf16` を使っている箇所がありますが、これは絵文字対策で入れたものです。これも、結構面倒臭かった…。

😭😭😭

# ＸＸ．まとめ

もしかしたら、バグあるかもしれないので、実装する場合は、自己責任でお願いします！

🙇‍♂️🙇‍♂️🙇‍♂️

あと、もっと簡単な方法があれば、教えて頂けるとと嬉しいです！

以上、ご参考になれば ♪♪♪

👋👋👋