LoginSignup
16
17

More than 5 years have passed since last update.

[iOS] UIAlertController の UITextField で文字入力があるまでボタンを押せないようにする

Last updated at Posted at 2014-12-12

UIAlertView が iOS8 で DEPRECATED されて、代わりに UIAlertController を利用する方法が推奨された。UIAlertView では iOS5 から UITextField を使った文字入力が可能になっていた。UIAlertController でも同様の機能は提供されている。

UIAlertController ではボタン押下時のアクションハンドラが delegate から Blocks を使った方法に変わった。そのため、UITextField の enabled プロパティに簡単にアクセスする手段がなくなった。UIAlertView では、文字入力があるまで「OK」などのボタンを押せなくできていたが、UIAlertController ではできなくなった。(不可能と言うよりは、簡単ではなくなった。)

以下、上記の問題を解決するために調査した内容を元に、汎用的に書き換えたソースコードの定型文を示す。自作のプログラムにそのまま取り込んで、文字列リテラルやボタン押下時などの必要な箇所を変更すれば、すぐに利用できるだろう。

-(void)prompt
{
   __weak typeof(self) weakSelf = self;

  @autoreleasepool {
    UIAlertController * alertController =
             [UIAlertController alertControllerWithTitle:@"新規フォルダ"
                                message:@"フォルダ名を入力して下さい"
                                preferredStyle:UIAlertControllerStyleAlert];

    void (^configurationHandler)(UITextField *) = ^(UITextField * textField) {
      textField.placeholder = @"フォルダ名";
      // ここで UITextField の text が変更したときの通知を受信する設定を実施
      [[NSNotificationCenter defaultCenter]
        addObserver:weakSelf
        selector:@selector(alertTextFieldDidChange:)
        name:UITextFieldTextDidChangeNotification
        object:textField];
    };
    [alertController addTextFieldWithConfigurationHandler:configurationHandler];

    void (^cancelHandler)(UIAlertAction *) = ^(UIAlertAction * action) {
      // UITextField 変更通知は不要
      [[NSNotificationCenter defaultCenter]
        removeObserver:weakSelf
        name:UITextFieldTextDidChangeNotification
        object:nil];
    };
    UIAlertAction * cancelAction =
             [UIAlertAction actionWithTitle:@"中止"
                            style:UIAlertActionStyleCancel
                            handler:cancelHandler];
    [alertController addAction:cancelAction];

    void (^createHandler)(UIAlertAction *) = ^(UIAlertAction * action) {
      UITextField * textField = alertController.textFields[0];
      if (textField.text.length > 0) {
        dispatch_block_t mainBlock = ^{
          // ここに UI の更新やデータベースへの追記などを実施するコードを記述する
        };
        dispatch_async(dispatch_get_main_queue(), mainBlock);
      }
      // 通知はもう要らない
      [[NSNotificationCenter defaultCenter]
        removeObserver:weakSelf
        name:UITextFieldTextDidChangeNotification
        object:nil];
    };
    UIAlertAction * createAction =
            [UIAlertAction actionWithTitle:@"作成"
                           style:UIAlertActionStyleDefault
                           handler:createHandler];
    createAction.enabled = NO; // 最初は「作成」ボタンは押せない
    [alertController addAction:createAction];

    [self presentViewController:alertController animated:YES completion:nil];
  }
}

#pragma mark - NSNotification handler
// ここで UITextField の入力処理を行う
-(void)alertTextFieldDidChange:(NSNotification *)notification
{
  UIAlertController * alertController = (UIAlertController *)self.presentedViewController;
  if (alertController) {
    UITextField *   textField    = alertController.textFields.firstObject;
    UIAlertAction * createAction = alertController.actions.lastObject;
    // 文字入力があればボタンを押せるようにする。
    // ここの値を 0 から 8 などにすれば、8文字以上の入力がないと有効にならないようにもできる。
    createAction.enabled = textField.text.length > 0;
  }
 }

ソースコードの利用は、上記をそのまま自作のプログラムにコピーした場合は、次の一文で呼び出せる。

[self prompt];

上記コードの NSNotification ハンドラの alertTextFieldDidChange 内の UITextFiled に対する条件処理を変更すれば、n文字以上m文字未満の場合など、簡単に応用可能である。以下は、よくあるパスワード入力の場合の修正箇所のコード。

void (^configurationHandler)(UITextField *) = ^(UITextField * textField) {
  textField.placeholder = @"";
  textField.secureTextEntry = YES; // 入力文字列を「*」でマスクする(追加部分!)

  [[NSNotificationCenter defaultCenter]
    addObserver:weakSelf
    selector:@selector(alertTextFieldDidChange:)
    name:UITextFieldTextDidChangeNotification
    object:textField];
};

#pragma mark - NSNotification handler
-(void)alertTextFieldDidChange:(NSNotification *)notification
{
  UIAlertController * alertController = (UIAlertController *)self.presentedViewController;
  if (alertController) {
    UITextField *   textField    = alertController.textFields.firstObject;
    UIAlertAction * createAction = alertController.actions.lastObject;
    // パスワードは 10文字以上の入力を必須とする。
    createAction.enabled = textField.text.length > 10; // (修正箇所!)
  }
}

定型文を使いまわせば、お手軽に応用ができるね。

16
17
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
16
17