LoginSignup
16
8

More than 5 years have passed since last update.

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

Posted at

はじめに

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

サンプル

キャレットの位置を取得する

  • currentCaretOffset

左から数えて、見た目上の何番目にキャレットがあるか返します。

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

キャレットを先頭・末尾に移動させる

  • caretMove(to: UITextViewDirection)

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

キャレットを現在の位置から移動させる

  • caretMove(to: Int)

現在の位置から指定の数を移動させます。
+ならば右方向へ、-なら左方向へ移動します。

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

キャレットの色を変更する

  • caretColor

実は好みで変数名を変えただけです。

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

文字を全て選択する

  • selectAllTexts()

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

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

文字を指定範囲にて選択する

  • selectTexts(start:length:)

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

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

文字が選択されているかどうか

  • isTextSelected

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

ソースコード

変数名などご自由に変更してください。 :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)
    }
}

参考にさせていただいた記事

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

16
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
8