Swift 4 UITextViewを便利に使うExtensionを書いてみた

# はじめに
こんにちは :leaves:
UITextViewを細かく制御しようと思った時、
調べた時に記事が少し古かったり、Swift4.0で名前が変わっていたりで少し悩んだので、まとめとして書いてみました。参考になれば幸いです。
`Apple Swift version 4.1` `Xcode Version 9.3.1`

# サンプル
## キャレットの位置を取得する
- **currentCaretOffset**

左から数えて、見た目上の何番目にキャレットがあるか返します。
<img width="300" src="https://qiita-image-store.s3.amazonaws.com/0/128250/54a105da-85cc-6dff-a415-8e495d2f7473.png">

```swift
// デフォルトにあるプロパティ
textView.selectedRange.location // 8
// Extension
textView.currentCaretOffset     // 7
```

## キャレットを先頭・末尾に移動させる
- **caretMove(to: UITextViewDirection)**

<img width="300" src="https://qiita-image-store.s3.amazonaws.com/0/128250/4e4bf038-910a-2137-b942-4b3cb77eba35.gif">

```swift
// ←ボタン 先頭へ移動します
textView.caretMove(to: .leading)
// →ボタン 末尾に移動します
textView.caretMove(to: .trailing)
```

## キャレットを現在の位置から移動させる
- **caretMove(to: Int)**

現在の位置から指定の数を移動させます。
`+`ならば右方向へ、`-`なら左方向へ移動します。
<img width="300" src="https://qiita-image-store.s3.amazonaws.com/0/128250/33a61842-4301-d4bc-1d95-f1e49ef49459.gif">

```swift
// →ボタン
textView.caretMove(to: 1)
// ←ボタン
textView.caretMove(to: -1)
```

## キャレットの色を変更する
- **caretColor**

実は好みで変数名を変えただけです。
<img width="300" src="https://qiita-image-store.s3.amazonaws.com/0/128250/fa4447f4-5b2e-c160-bc88-31e2b5083c22.gif">

```swift
// キャレットを緑色に変更する
textView.caretColor = UIColor.green
```

## 文字を全て選択する
- **selectAllTexts()**

UITextView内の文字を全て選択します。

<img width="300" src="https://qiita-image-store.s3.amazonaws.com/0/128250/aff05292-a3d8-8323-ca38-dbc7101ae5a5.gif">

```swift
// 文字全てを選択します
textView.selectAllTexts()
```

## 文字を指定範囲にて選択する
- **selectTexts(start:length:)**

startは開始位置、lengthは選択する範囲です。

<img width="300" src="https://qiita-image-store.s3.amazonaws.com/0/128250/43e0a895-3c86-e66f-96ff-98da6d848d0b.png">

```swift
// 見た目上の文字の長さから選択します
textView.selectTexts(start: 0, length: 7)
```

## 文字が選択されているかどうか
- **isTextSelected**

`UITextRange`の`isEmpty`は以下の画像のようになっていて、それを少しだけ改良してみました。

<img width="400" src="https://qiita-image-store.s3.amazonaws.com/0/128250/9781a309-a8c0-f94e-b35e-ab870daeb9ea.png">

# ソースコード
変数名などご自由に変更してください。 :ear_of_rice:

```UITextFieldExt.swift
import UIKit

extension UITextView {
    
    enum UITextViewDirection {
        case leading
        case trailing
    }
    
    // キャレットの色を変更します
    var caretColor: UIColor {
        get { return self.tintColor }
        set { self.tintColor = newValue}
    }
    
    // 文字が選択されているかどうか
    var isTextSelected: Bool {
        guard let range = selectedTextRange else { return false }
        return !range.isEmpty
    }
    
    // 先頭から数えたキャレットの見た目上の文字の位置を示します
    var currentCaretOffset: Int {
        let current = selectedRange.location
        let diff = text.length - text.count
        return current - diff
    }
    
    // キャレットを移動させます
    func caretMove(to direction: UITextViewDirection) {
        switch direction {
        case .leading:
            self.selectedTextRange = textRange(from: beginningOfDocument, to: beginningOfDocument)
        case .trailing:
            self.selectedTextRange = textRange(from: endOfDocument, to: endOfDocument)
        }
    }
    
    // キャレットを移動させます
    func caretMove(to offset: Int) {
        let current = selectedRange.location
        let to = current + offset
        self.selectedRange = NSRange(location: to, length: 0)
    }
    
    // 文字全てを選択します
    func selectAllTexts() {
        self.selectedTextRange = textRange(from: beginningOfDocument, to: endOfDocument)
    }
    
    // 見た目上の文字の長さから選択します
    func selectTexts(start: Int = 0, length: Int) {
        let diff = text.length - text.count
        self.selectedRange = NSRange(location: start, length: length + diff)
    }
    
    // NSRangeとして取得します
    var selectedTextNSRange: NSRange? {
        guard let range = selectedTextRange else { return nil }
        let location = offset(from: beginningOfDocument, to: range.start)
        let length = offset(from: range.start, to: range.end)
        return NSRange(location: location, length: length)
    }
}
```

# 参考にさせていただいた記事
- [UITextField apple](https://developer.apple.com/documentation/uikit/uitextfield)

- [UITextFieldのキャレットを操作（UITextRangeとUITextPosition)　the moon at dawn](http://glayash.blogspot.jp/2012/08/uitextfielduitextrageuitextposition.html)

見て頂いてありがとうございます。