しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

UITextFieldの変更通知を受け取る方法

UITextFieldでユーザーが何か入力した時のイベントを取る方法です。

shouldChangeCharactersInRange

方法は2つありまして、1つ目はUITextFieldDelegatedelegateメソッドであるtextField:shouldChangeCharactersInRange:を使う方法です。

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGrayColor()
        let tf = UITextField()
        tf.delegate = self
        tf.frame = CGRect(x: 10, y: 10, width: 100, height: 40)
        tf.backgroundColor = UIColor.whiteColor()
        view.addSubview(tf)
    }
}

extension ViewController: UITextFieldDelegate {
    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        // 変更があるとここに来る
        
        return true
    }
}

shouldChangeCharactersInRangeはfalseを返すとユーザーの入力を無効化できるので、「文字数が10文字以上だったらユーザーに入力させない」と言った事もできます。

extension ViewController: UITextFieldDelegate {
    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        let text = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
        if text.characters.count > 10 { return false }
        
        return true
    }
}

しかしこの方法だと、ユーザーの入力後の文字を取得するのにstringByReplacingCharactersInRangeを使う必要があるのがめんどくさいです。

それと変換中のバックキー押下時のイベントがうまく取れない問題があります。

↓ この状態でバックキーを押すとstringByReplacingCharactersInRangeで正しく文字が取れない。
f:id:llcc:20151115005442p:plain

UIControlEvents.EditingChanged

2つ目の方法はUIControlEvents.EditingChangedを利用する方法です。
.EditingChangedなら入力後の文字列を取得できるので、上記の2つの問題を回避できます。

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGrayColor()
        let tf = UITextField()
        
        tf.addTarget(self, action: "textFieldEditingChanged:", forControlEvents: .EditingChanged)
        tf.frame = CGRect(x: 10, y: 10, width: 100, height: 40)
        tf.backgroundColor = UIColor.whiteColor()
        view.addSubview(tf)
    }
}

extension ViewController {
    func textFieldEditingChanged(sender: UITextField) {
        print(sender.text) // ユーザーの入力完了後の文字が入ってる
    }
}

まとめ

普通に変更イベントを取りたいだけならEditingChanged、場合によってユーザーの入力をキャンセルしたい場合はshouldChangeCharactersInRangeと使い分けると良さそうです。