Saya menambahkan UITextField
ke UIAlertController
, yang muncul sebagai AlertView
. Sebelum mengabaikan UIAlertController
, saya ingin memvalidasi input UITextField
. Berdasarkan validasi saya ingin mengabaikan UIAlertController
atau tidak. Tapi saya tidak tahu bagaimana mencegah tindakan pemberhentian UIAlertController
saat tombol ditekan. Adakah yang bisa memecahkan masalah ini atau ada ide harus mulai dari mana? Saya pergi ke Google tetapi tidak berhasil :/ Terima kasih!
Cegah pemberhentian UIAlertController
Jawaban (5)
Anda benar: jika pengguna dapat mengetuk tombol di lansiran Anda, lansiran tersebut akan ditutup. Jadi, Anda ingin mencegah pengguna mengetuk tombol! Ini semua hanya masalah menonaktifkan tombol UIAlertAction Anda. Jika tindakan peringatan dinonaktifkan, pengguna tidak dapat mengetuknya untuk menutupnya.
Untuk menggabungkan ini dengan validasi bidang teks, gunakan metode delegasi bidang teks atau metode tindakan (dikonfigurasi dalam pengendali konfigurasi bidang teks saat Anda membuatnya) untuk mengaktifkan/menonaktifkan UIAlertActions dengan tepat bergantung pada teks apa yang telah (atau belum) dimasukkan .
Berikut ini contohnya. Kami membuat bidang teks seperti ini:
alert.addTextFieldWithConfigurationHandler {
(tf:UITextField!) in
tf.addTarget(self, action: "textChanged:", forControlEvents: .EditingChanged)
}
Kami memiliki tindakan Batal dan tindakan OK, dan kami menonaktifkan tindakan OK:
(alert.actions[1] as UIAlertAction).enabled = false
Selanjutnya, pengguna tidak dapat mengetuk OK kecuali ada teks sebenarnya di bidang teks:
func textChanged(sender:AnyObject) {
let tf = sender as UITextField
var resp : UIResponder = tf
while !(resp is UIAlertController) { resp = resp.nextResponder() }
let alert = resp as UIAlertController
(alert.actions[1] as UIAlertAction).enabled = (tf.text != "")
}
EDIT Berikut versi kode di atas saat ini (Swift 3.0.1 dan yang lebih baru):
alert.addTextField { tf in
tf.addTarget(self, action: #selector(self.textChanged), for: .editingChanged)
}
Dan
alert.actions[1].isEnabled = false
Dan
@objc func textChanged(_ sender: Any) {
let tf = sender as! UITextField
var resp : UIResponder! = tf
while !(resp is UIAlertController) { resp = resp.next }
let alert = resp as! UIAlertController
alert.actions[1].isEnabled = (tf.text != "")
}
Saya telah menyederhanakan jawaban matt tanpa melintasi hierarki tampilan. Ini menjadikan tindakan itu sendiri sebagai variabel lemah. Ini adalah contoh yang berfungsi penuh:
weak var actionToEnable : UIAlertAction?
func showAlert()
{
let titleStr = "title"
let messageStr = "message"
let alert = UIAlertController(title: titleStr, message: messageStr, preferredStyle: UIAlertControllerStyle.Alert)
let placeholderStr = "placeholder"
alert.addTextFieldWithConfigurationHandler({(textField: UITextField) in
textField.placeholder = placeholderStr
textField.addTarget(self, action: "textChanged:", forControlEvents: .EditingChanged)
})
let cancel = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: { (_) -> Void in
})
let action = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: { (_) -> Void in
let textfield = alert.textFields!.first!
//Do what you want with the textfield!
})
alert.addAction(cancel)
alert.addAction(action)
self.actionToEnable = action
action.enabled = false
self.presentViewController(alert, animated: true, completion: nil)
}
func textChanged(sender:UITextField) {
self.actionToEnable?.enabled = (sender.text! == "Validation")
}
Mengutip jawaban @ Matt, inilah cara saya melakukan hal yang sama di Obj-C
- (BOOL)textField: (UITextField*) textField shouldChangeCharactersInRange: (NSRange) range replacementString: (NSString*)string
{
NSString *newString = [textField.text stringByReplacingCharactersInRange: range withString: string];
// check string length
NSInteger newLength = [newString length];
BOOL okToChange = (newLength <= 16); // don't allow names longer than this
if (okToChange)
{
// Find our Ok button
UIResponder *responder = textField;
Class uiacClass = [UIAlertController class];
while (![responder isKindOfClass: uiacClass])
{
responder = [responder nextResponder];
}
UIAlertController *alert = (UIAlertController*) responder;
UIAlertAction *okAction = [alert.actions objectAtIndex: 0];
// Dis/enable Ok button based on same-name
BOOL duplicateName = NO;
// <check for duplicates, here>
okAction.enabled = !duplicateName;
}
return (okToChange);
}
Saya menyadari bahwa ini ada di Objectiv-C tetapi ini menunjukkan prinsipnya. Saya akan memperbarui ini dengan versi cepat nanti.
Anda juga bisa melakukan hal yang sama dengan menggunakan blok sebagai target.
Tambahkan properti ke ViewController
Anda sehingga blok (penutupan untuk Swift) memiliki referensi yang kuat
@property (strong, nonatomic) id textValidationBlock;
Kemudian buat AlertViewController
seperti ini:
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Title" message:@"Message" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}];
__weak typeof(self) weakSelf = self;
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[weakSelf doSomething];
}];
[alertController addAction:cancelAction];
[alertController addAction:okAction];
[alertController.actions lastObject].enabled = NO;
self.textValidationBlock = [^{
UITextField *textField = [alertController.textFields firstObject];
if (something) {
alertController.message = @"Warning message";
[alertController.actions lastObject].enabled = NO;
} else if (somethingElse) {
alertController.message = @"Another warning message";
[alertController.actions lastObject].enabled = NO;
} else {
//Validation passed
alertController.message = @"";
[alertController.actions lastObject].enabled = YES;
}
} copy];
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.placeholder = @"placeholder here";
[textField addTarget:weakSelf.textValidationBlock action:@selector(invoke) forControlEvents:UIControlEventEditingChanged];
}];
[self presentViewController:alertController animated:YES completion:nil];
Inilah ide yang sama seperti jawaban lainnya, tetapi saya ingin metode sederhana diisolasi dalam ekstensi dan tersedia untuk digunakan di subkelas UIViewController mana pun. Ini menunjukkan peringatan dengan satu kolom input teks dan dua tombol: ok dan batal.
extension UIViewController {
func askForTextAndConfirmWithAlert(title: String, placeholder: String, okHandler: @escaping (String?)->Void) {
let alertController = UIAlertController(title: title, message: nil, preferredStyle: .alert)
let textChangeHandler = TextFieldTextChangeHandler { text in
alertController.actions.first?.isEnabled = !(text ?? "").isEmpty
}
var textHandlerKey = 0
objc_setAssociatedObject(self, &textHandlerKey, textChangeHandler, .OBJC_ASSOCIATION_RETAIN)
alertController.addTextField { textField in
textField.placeholder = placeholder
textField.clearButtonMode = .whileEditing
textField.borderStyle = .none
textField.addTarget(textChangeHandler, action: #selector(TextFieldTextChangeHandler.onTextChanged(sender:)), for: .editingChanged)
}
let okAction = UIAlertAction(title: CommonLocStr.ok, style: .default, handler: { _ in
guard let text = alertController.textFields?.first?.text else {
return
}
okHandler(text)
objc_setAssociatedObject(self, &textHandlerKey, nil, .OBJC_ASSOCIATION_RETAIN)
})
okAction.isEnabled = false
alertController.addAction(okAction)
alertController.addAction(UIAlertAction(title: CommonLocStr.cancel, style: .cancel, handler: { _ in
objc_setAssociatedObject(self, &textHandlerKey, nil, .OBJC_ASSOCIATION_RETAIN)
}))
present(alertController, animated: true, completion: nil)
}
}
class TextFieldTextChangeHandler {
let handler: (String?)->Void
init(handler: @escaping (String?)->Void) {
self.handler = handler
}
@objc func onTextChanged(sender: AnyObject) {
handler((sender as? UITextField)?.text)
}
}