6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

横画面でTextViewの文字数制限をする時に気をつけること

Posted at

TextView内で文字数制限をしたいことがあると思いますが、横画面対応してるアプリである条件の時にクラッシュしたため、気をつけることをまとめました。

環境

  • Xcode10.1
  • Swift4.2

文字制限コード

基本的な文字数制限のコードは以下のように書けます。

ViewController.swift
import UIKit

class ViewController: UIViewController {
    enum Const {
        static let maxStringCount = 5
    }
    
    @IBOutlet var textView: UITextView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        textView.delegate = self
    }
}

extension ViewController: UITextViewDelegate {
    func textViewDidChange(_ textView: UITextView) {
        guard let text = textView.text else { return }

            if textView.markedTextRange == nil && textView.text.count > Const.maxStringCount {
            let endIndex = text.index(text.startIndex, offsetBy: Const.maxStringCount)
            textView.text = String(text[..<endIndex])
        }
    }
}

動作GIFは以下のようになります。
first.gif

注意点

しかしこれだと、iPhoneの横画面やiPadの場合、キーボード入力でUndo・Redoした際にクラッシュします。
Undoとは以下のスクリーンショットのオレンジ色の部分です。

Undoスクリーンショット
iPhone iPad

上記のコードのままUndoを押すと、クラッシュします。
crash.gif

対策

Undo・Redo中なのかどうかを判断するため、textDidChange内でtextView.undoManger.isUndoingtextView.undoManger.isRedoingを条件に追加します。

完成コード

ViewController.swift
import UIKit

class ViewController: UIViewController {
    enum Const {
        static let maxStringCount = 5
    }
    
    @IBOutlet var textView: UITextView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        textView.delegate = self
    }
}

extension ViewController: UITextViewDelegate {
    func textViewDidChange(_ textView: UITextView) {
        guard let text = textView.text,
            let isUndoing = textView.undoManager?.isUndoing,
            let isRedoing = textView.undoManager?.isRedoing else { return }
        
        if !isUndoing
            && !isRedoing
            && textView.markedTextRange == nil
            && textView.text.count > Const.maxStringCount {
            let endIndex = text.index(text.startIndex, offsetBy: Const.maxStringCount)
            textView.text = String(text[..<endIndex])
        }
    }
}

動作GIF

Undoしても問題なく動作します。

動作 動作GIF
文字数オーバー→確定 success.gif
文字数オーバー→Undo undo_success.gif
6
3
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
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?