Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

こんにちは :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)
    }
}

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

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

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away