仅在验证输入后启用 UIAlertController 的 UIAlertAction
Enable UIAlertAction of UIAlertController only after input is validated
我正在使用 UIAlertController
显示一个带有 UITextField
和一个标记为 "Ok" 的 UIAlertAction
按钮的对话框。在 UITextField
中输入多个字符(比如 5 个字符)之前,如何禁用该按钮?
在头文件中添加以下内容属性
@property(nonatomic, strong)UIAlertAction *okAction;
然后将以下代码复制到 ViewController
的 viewDidLoad
方法中
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];
还在您的 Class
中实现以下 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;
}
这应该有效
您可以在 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;
}
}
更好的方法是在验证输入后提醒用户他的输入有什么问题,这样用户就知道应用程序对他的期望是什么。
- (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;
}
Swift 3 实现基于 soulshined 的回答:
var someAlert: UIAlertController {
let alert = UIAlertController(title: "Some Alert", message: nil, preferredStyle: .alert)
alert.addTextField {
[=10=].placeholder = "Write something"
[=10=].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
}
}
我已经 an answer for another post asking basically the same question on Whosebug. To summarize, there are several ways to do this: use UITextFieldDelegate, Notification, KVO, or plainly add event handling target on the control. My solution is 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
}
如果您在项目中必须多次处理此类警报,这应该很方便。
使用 Swift 5.3 和 iOS 14,您可以使用 Combine 框架和 NotificationCenter
跟踪给定 UITextField
的 UITextField.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)
}
}
我正在使用 UIAlertController
显示一个带有 UITextField
和一个标记为 "Ok" 的 UIAlertAction
按钮的对话框。在 UITextField
中输入多个字符(比如 5 个字符)之前,如何禁用该按钮?
在头文件中添加以下内容属性
@property(nonatomic, strong)UIAlertAction *okAction;
然后将以下代码复制到 ViewController
viewDidLoad
方法中
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];
还在您的 Class
中实现以下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;
}
这应该有效
您可以在 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;
}
}
更好的方法是在验证输入后提醒用户他的输入有什么问题,这样用户就知道应用程序对他的期望是什么。
- (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;
}
Swift 3 实现基于 soulshined 的回答:
var someAlert: UIAlertController {
let alert = UIAlertController(title: "Some Alert", message: nil, preferredStyle: .alert)
alert.addTextField {
[=10=].placeholder = "Write something"
[=10=].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
}
}
我已经 an answer for another post asking basically the same question on Whosebug. To summarize, there are several ways to do this: use UITextFieldDelegate, Notification, KVO, or plainly add event handling target on the control. My solution is 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
}
如果您在项目中必须多次处理此类警报,这应该很方便。
使用 Swift 5.3 和 iOS 14,您可以使用 Combine 框架和 NotificationCenter
跟踪给定 UITextField
的 UITextField.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)
}
}