LoginSignup
11
6

More than 5 years have passed since last update.

バリデーション&エラー表示付きの入力フォームを作ってみる

Posted at

概要

animation

この記事では、AndroidのTextInputLayoutのように、エラー表示付きの入力フォームを作る方法について説明します。ついでに、入力値のバリデーションも行います。

サンプル

Text-Input-Layout@githubに動作するプロジェクトがあります。

仕組み

TextInputView

image1

タイトルラベル、必須マークラベル、テキストフィールド、エラーラベルを持つカスタムビューとTextInputViewを用意します。

クラス全体をIBDesignable、title, isRequired, placeholder, errorMessageを@IBInspectableとし、Interface Builderから値を入力できるようにします。
また、computed propertyとして、isValidatedを宣言します。isValidatedを呼ぶと、バリデーションを行い、必要に応じてエラーを表示します。
これにより、呼び出し元は、TextInputValidationTypeを最初に設定すれば、バリデーションロジックやエラーの表示・非表示を気にする必要はありません。

enum TextInputValidationType: Int {
    case none
    case email
}

@IBDesignable
class TextInputView: UIView {
    @IBOutlet fileprivate weak var titleLabel: UILabel!
    @IBOutlet fileprivate weak var titleViewWidthConstraint: NSLayoutConstraint!
    @IBOutlet fileprivate weak var requiredLabel: UILabel!
    @IBOutlet weak var textField: UITextField!
    @IBOutlet fileprivate weak var errorLabel: UILabel!

    @IBInspectable var title: String = "" {
        didSet {
            titleLabel?.text = title
            titleLabel?.sizeToFit()
            titleViewWidthConstraint?.constant = titleLabel.frame.width
        }
    }
    @IBInspectable var isRequired: Bool = true {
        didSet {
            requiredLabel?.isHidden = !isRequired
        }
    }
    @IBInspectable var placeholder: String = "" {
        didSet {
            textField?.placeholder = placeholder
        }
    }
    @IBInspectable var errorMessage: String = "" {
        didSet {
            errorLabel?.text = errorMessage
        }
    }

    var validationType: TextInputValidationType = .none
    var text: String {
        return textField?.text ?? ""
    }
    var isValidated: Bool {
        errorLabel.isHidden = true
        switch validationType {
        case .email:
            errorLabel.isHidden = isEmail(text: text)
        default:
            break
        }

        if text.isEmpty {
            errorLabel.isHidden = !isRequired
        }

        return errorLabel.isHidden
    }
}

TextInputViewの使い方

Interface Builder上でUIViewを追加し、ClassをTextInputViewに設定します。
そうすると、IBInspectableを設定したプロパティをInterface Builder上から操作できることがわかります。isRequiredをOn(true)にすると、(Required)が表示されていることがわかります。

image2

逆にisRequiredをOff(false)にすると、(Required)が非表示になったことがわかります。

image3

呼び出し元では、validationTypeやtextFieldのキーボードタイプを指定します。
また、isValidatedを呼び出すことで、バリデーション条件をクリアしているかを知ることができます。
このように、TextInputView側にバリデーションやエラー表示の処理を任せることで、呼び出し元は、スッキリとしたコードとなります。
(ちなみに、IBInspectableに、enum型を指定することができれば、より簡易に書けそうですが、現状はできません。)

class ViewController: UIViewController {
    @IBOutlet fileprivate weak var emailTextInputView: TextInputView!
    @IBOutlet fileprivate var textInputViews: [TextInputView]!
    @IBOutlet fileprivate weak var resultLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        emailTextInputView.validationType = .email
        emailTextInputView.textField.keyboardType = .emailAddress
        emailTextInputView.textField.returnKeyType = .done
    }

    @IBAction private func onValidationButtonClick(_ sender: UIButton) {
        let areValidated = !textInputViews.map({ $0.isValidated }).contains(false)
        resultLabel.text = areValidated ? "Validated :)" : "Invalidated :("
    }
}

サンプル

Text-Input-Layout@githubに動作するプロジェクトがあります。

11
6
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
11
6