仅在验证输入后启用 UIAlertController 的 UIAlertAction

Posted

技术标签:

【中文标题】仅在验证输入后启用 UIAlertController 的 UIAlertAction【英文标题】:Enable UIAlertAction of UIAlertController only after input is validated 【发布时间】:2015-08-30 16:22:02 【问题描述】:

我正在使用UIAlertController 显示一个对话框,其中包含一个UITextField 和一个标记为“Ok”的UIAlertAction 按钮。如何在UITextField 中输入多个字符(比如 5 个字符)之前禁用该按钮?

【问题讨论】:

你需要检查 UITextField 长度 .. 如果 UITextField 长度为 5 则按钮将启用其他方式不 【参考方案1】:

您可以将观察者添加到您的UITextField

[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) 
    [textField addTarget:self action:@selector(alertControllerTextFieldDidChange:) forControlEvents:UIControlEventEditingChanged];

但首先禁用您的按钮:

okAction.enabled = NO;

然后在你指定的方法中验证它:

- (void)alertTextFieldDidChange:(UITextField *)sender 
  UIAlertController *alertController = (UIAlertController *)self.presentedViewController;
  if (alertController) 
    UITextField *someTextField = alertController.textFields.firstObject;
    UIAlertAction *okAction = alertController.actions.lastObject;
    okAction.enabled = someTextField.text.length > 2;
  

【讨论】:

【参考方案2】:

在头文件中添加以下属性

@property(nonatomic, strong)UIAlertAction *okAction;   

然后在ViewControllerviewDidLoad 方法中复制以下代码

self.okAction = [UIAlertAction actionWithTitle:@"OK"
                                         style:UIAlertActionStyleDefault
                                       handler:nil];
self.okAction.enabled = NO;

UIAlertController *controller = [UIAlertController alertControllerWithTitle:nil
                                                                    message:@"Enter your text"
                                                             preferredStyle:UIAlertControllerStyleAlert];

[controller addTextFieldWithConfigurationHandler:^(UITextField *textField) 

    textField.delegate = self;
];

[controller addAction:self.okAction];
[self presentViewController:controller animated:YES completion:nil];

还在你的类中实现以下 UITextField 委托方法

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

    NSString *finalString = [textField.text stringByReplacingCharactersInRange:range withString:string];
   [self.okAction setEnabled:(finalString.length >= 5)];
   return YES;

这应该可以工作

【讨论】:

您可能还想添加:- (BOOL) textFieldShouldClear:(UITextField *)textField [self.okAction setEnabled:NO]; return YES; 【参考方案3】:

基于 soulshined 的回答的 Swift 3 实现:

var someAlert: UIAlertController 
    let alert = UIAlertController(title: "Some Alert", message: nil, preferredStyle: .alert)

    alert.addTextField 
        $0.placeholder = "Write something"
        $0.addTarget(self, action: #selector(self.textFieldTextDidChange(_:)), for: .editingChanged)
    

    alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))

    let submitAction = UIAlertAction(title: "Submit", style: .default)  _ in
        // Do something...
    

    submitAction.isEnabled = false
    alert.addAction(submitAction)
    return alert


func textFieldTextDidChange(_ textField: UITextField) 
    if let alert = presentedViewController as? UIAlertController,
        let action = alert.actions.last,
        let text = textField.text 
        action.isEnabled = text.characters.count > 0
    

【讨论】:

你应该在.addTextField(configurationHandler里面设置textField.delegate = self【参考方案4】:

借助 Swift 5.3 和 ios 14,您可以使用组合框架和 NotificationCenter 来跟踪给定 UITextFieldUITextField.textDidChangeNotification 通知。


以下代码显示了一个可能的实现,以便根据textField 的字符数启用UIAlertController 的按钮:

import UIKit
import Combine

class ViewController: UIViewController 

    var cancellable: AnyCancellable?

    override func viewDidLoad() 
        super.viewDidLoad()

        view.backgroundColor = .systemBackground

        let action = UIAction(
            title: "Change title",
            handler:  [unowned self] _ in
                self.presentAlert()
            
        )
        let barButtonItem = UIBarButtonItem(primaryAction: action)
        navigationItem.rightBarButtonItem = barButtonItem
    


extension ViewController 

    func presentAlert() 
        let alertController = UIAlertController(
            title: "Change title",
            message: nil,
            preferredStyle: .alert
        )
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)  _ in
            print("Cancelled")
        
        let renameAction = UIAlertAction(
            title: "Rename",
            style: .default
        )  [unowned alertController] action in
            print("Renamed: \(alertController.textFields!.first!.text!)")
        
        renameAction.isEnabled = false

        alertController.addAction(cancelAction)
        alertController.addAction(renameAction)
        alertController.addTextField(configurationHandler:  textField in
            self.cancellable = NotificationCenter.default
                .publisher(for: UITextField.textDidChangeNotification, object: textField)
                .sink(receiveValue:  _ in
                    let textCount = textField.text?.trimmingCharacters(in: .whitespacesAndNewlines).count ?? 0
                    renameAction.isEnabled = textCount >= 5 // min 5 characters
                )
        )
        present(alertController, animated: true)
    


【讨论】:

【参考方案5】:

更好的方法是在验证用户的输入后提醒用户他的输入有什么问题,以便用户知道应用对他的期望。

- (void)askReasonWithPreviousReason:(NSString *)text

    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Alert" message:@"Enter reason" preferredStyle:UIAlertControllerStyleAlert];

    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField)
     
         textField.text = text;
     ];

    [alertController addAction:[UIAlertAction actionWithTitle:@"Save" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action)
                                
                                    if ([self isReasonValid:alertController.textFields.firstObject.text])
                                    
                                        UIAlertController *alertController2 = [UIAlertController alertControllerWithTitle:AlertTitle message:@"Are you sure you would like to save?" preferredStyle:UIAlertControllerStyleAlert];

                                        [alertController2 addAction:[UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action)
                                                                     
                                                                         [self saveReason:alertController.textFields.firstObject.text];
                                                                     ]];
                                        [alertController2 addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:Nil]];

                                        [self presentViewController:alertController2 animated:YES completion:nil];
                                    
                                ]];

    [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:Nil]];

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


- (BOOL)isReasonValid:(NSString *)reason

    NSString *errorMessage = [[NSString alloc] init];

    if (reason.length < 5)
    
        errorMessage = @"Reason must be more than 5 characters";
    
    else if (reason.length > 100)
    
        errorMessage = @"Reason must be less than 100 characters";
    

    if (errorMessage.length != 0)
    
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Alert" message:errorMessage preferredStyle:UIAlertControllerStyleAlert];

        [alertController addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action)
                                    
                                        [self askReasonWithPreviousReason:reason];
                                    ]];

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

        return NO;
    

    return YES;

【讨论】:

【参考方案6】:

我有 an answer 的另一篇帖子在 *** 上提出了基本相同的问题。总而言之,有几种方法可以做到这一点:使用 UITextFieldDelegate、Notification、KVO,或者在控件上简单地添加事件处理目标。我的解决方案是 a simple UIAlertController subclass 包裹在事件处理目标周围,您可以通过调用简单地配置

    alert.addTextField(configurationHandler:  (textField) in
        textField.placeholder = "Your name"
        textField.autocapitalizationType = .words
    )  (textField) in
        saveAction.isEnabled = (textField.text?.characters.count ?? 0) > 0
    

如果您必须在项目中多次处理此类警报,这应该很方便。

【讨论】:

以上是关于仅在验证输入后启用 UIAlertController 的 UIAlertAction的主要内容,如果未能解决你的问题,请参考以下文章

流明仅在验证后才抛出 CORS

条纹,验证卡并仅在操作后对其进行收费

在输入时逐字母地验证UITextField文本

如何仅在 Spring 中为微服务项目的外部客户端启用身份验证?

仅在启用按钮时输入

如何启用/禁用提交按钮,仅在提供两个条件的情况下:检查输入单选和填充输入文本