【Swift】UITextViewに文字数制限と行数制限を加える方法
この記事ではUITextViewに文字数制限と行数制限を加える方法を書いていきます。
この記事ではUITextViewに以下の制限を加えていきます。
- 最大文字数55文字
- 最大行数3行
基本的には文字数制限だけで十分な場合が多いと思うのですが、極端な話、それだけですと最大文字数の数だけ改行が出来てしまいます。最終的に出力するUILabelの高さを揃えたい時などに行数制限は役立つかもしれません。
以下、完成イメージです。
それでは早速Viewの準備から入ります。
1. 準備
用意するのは
- 残り文字数を表示するためのUILabel(wordCountLabel)
- 最大文字数を表示するためのUILabel
- テキスト入力用のUITextView(textView)
①と③は対応するViewControllerにoutletとして紐付けます。
storybordは↓のようになっています。
2. UITextViewに文字数制限を加える
2-1.文字数制限
文字数制限にはUITextViewのdelegate methodの一つ、shouldChangeTextIn rangeを使います。textViewのdelegateを対応するViewControllerに渡し、以下を加えます。
1 2 3 |
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { return textView.text.count + (text.count - range.length) <= 55 } |
2-2.残り文字カウント
なんの表記もなくいきなり入力出来なくなったらユーザー体験的にもよくないので、残り文字カウントも付け足します。
1 2 3 |
func textViewDidChange(_ textView: UITextView) { self.wordCountLabel.text = "\(55 - textView.text.count)" } |
2-3.プレイスホルダー
UITextViewにはUITextFieldみたいにplaceholderが無いので自前で用意します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
func textViewDidBeginEditing(_ textView: UITextView) { if textView.text == "テキストを入力・・・" { textView.text = nil textView.textColor = .darkText } } func textViewDidEndEditing(_ textView: UITextView) { if textView.text.isEmpty { textView.textColor = .darkGray textView.text = "テキストを入力・・・" } } |
現状ViewControllerは以下のようになっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
import UIKit class ViewController: UIViewController { @IBOutlet weak var wordCountLabel: UILabel! @IBOutlet weak var textView: UITextView! fileprivate var maxWordCount: Int = 55 //最大文字数 fileprivate let placeholder: String = "テキストを入力・・・" //プレイスホルダー override func viewDidLoad() { super.viewDidLoad() self.textView.delegate = self //タップでキーボードを下げる let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) self.view.addGestureRecognizer(tapGesture) //下にスワイプでキーボードを下げる let swipeDownGesture = UISwipeGestureRecognizer(target: self, action: #selector(dismissKeyboard)) swipeDownGesture.direction = .down self.view.addGestureRecognizer(swipeDownGesture) } @objc func dismissKeyboard() { self.view.endEditing(true) } } extension ViewController: UITextViewDelegate { func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { return textView.text.count + (text.count - range.length) <= maxWordCount } func textViewDidChange(_ textView: UITextView) { self.wordCountLabel.text = "\(maxWordCount - textView.text.count)" } func textViewDidBeginEditing(_ textView: UITextView) { if textView.text == placeholder { textView.text = nil textView.textColor = .darkText } } func textViewDidEndEditing(_ textView: UITextView) { if textView.text.isEmpty { textView.textColor = .darkGray textView.text = placeholder } } } |
3. UITextViewに行数制限を加える
まずは文字数制限が無い状態で行数制限を加え、あとで2つを組み合わせます。行数制限ではshouldChangeTextIn rangeを以下のようにします。
1 2 3 4 5 6 |
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { let existingLines = textView.text.components(separatedBy: .newlines)//既に存在する改行数 let newLines = text.components(separatedBy: .newlines)//新規改行数 let linesAfterChange = existingLines.count + newLines.count - 1 //最終改行数。-1は編集したら必ず1改行としてカウントされるため。 return linesAfterChange <= 3 } |
4. 全てを組み合わせる
文字数制限と行数制限を合わせると以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { let existingLines = textView.text.components(separatedBy: .newlines)//既に存在する改行数 let newLines = text.components(separatedBy: .newlines)//新規改行数 let linesAfterChange = existingLines.count + newLines.count - 1 //最終改行数。-1は編集したら必ず1改行としてカウントされるから。 return linesAfterChange <= 3 && textView.text.count + (text.count - range.length) <= maxWordCount } func textViewDidChange(_ textView: UITextView) { let existingLines = textView.text.components(separatedBy: .newlines)//既に存在する改行数 if existingLines.count <= 3 { self.wordCountLabel.text = "\(maxWordCount - textView.text.count)" } } |
最終的にViewControllerは以下のようになっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
import UIKit class ViewController: UIViewController { @IBOutlet weak var wordCountLabel: UILabel! @IBOutlet weak var textView: UITextView! fileprivate var maxWordCount: Int = 55 //最大文字数 fileprivate let placeholder: String = "テキストを入力・・・" //プレイスホルダー override func viewDidLoad() { super.viewDidLoad() self.textView.delegate = self //タップでキーボードを下げる let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) self.view.addGestureRecognizer(tapGesture) //下にスワイプでキーボードを下げる let swipeDownGesture = UISwipeGestureRecognizer(target: self, action: #selector(dismissKeyboard)) swipeDownGesture.direction = .down self.view.addGestureRecognizer(swipeDownGesture) } @objc func dismissKeyboard() { self.view.endEditing(true) } } extension ViewController: UITextViewDelegate { func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { let existingLines = textView.text.components(separatedBy: .newlines)//既に存在する改行数 let newLines = text.components(separatedBy: .newlines)//新規改行数 let linesAfterChange = existingLines.count + newLines.count - 1 //最終改行数。-1は編集したら必ず1改行としてカウントされるから。 return linesAfterChange <= 3 && textView.text.count + (text.count - range.length) <= maxWordCount } func textViewDidChange(_ textView: UITextView) { let existingLines = textView.text.components(separatedBy: .newlines)//既に存在する改行数 if existingLines.count <= 3 { self.wordCountLabel.text = "\(maxWordCount - textView.text.count)" } } func textViewDidBeginEditing(_ textView: UITextView) { if textView.text == placeholder { textView.text = nil textView.textColor = .darkText } } func textViewDidEndEditing(_ textView: UITextView) { if textView.text.isEmpty { textView.textColor = .darkGray textView.text = placeholder } } } |
以上、UITextViewに文字数制限と行数制限を加える方法でした。