ป้องกันการเลิกจ้าง UIAlertController

ฉันกำลังเพิ่ม UITextField ไปที่ UIAlertController ซึ่งปรากฏเป็น AlertView ก่อนที่จะยกเลิก UIAlertController ฉันต้องการตรวจสอบอินพุตของ UITextField จากการตรวจสอบความถูกต้อง ฉันต้องการยกเลิก UIAlertController หรือไม่ แต่ฉันไม่รู้ว่าจะป้องกันการยกเลิกการทำงานของ UIAlertController ได้อย่างไรเมื่อกดปุ่ม มีใครแก้ไขปัญหานี้หรือความคิดใด ๆ ที่จะเริ่มต้น? ฉันไปที่ Google แต่โชคไม่ดี :/ ขอบคุณ!


person jona jürgen    schedule 02.09.2014    source แหล่งที่มา


คำตอบ (5)


คุณพูดถูก: หากผู้ใช้สามารถแตะปุ่มในการแจ้งเตือนของคุณได้ การแจ้งเตือนนั้นก็จะถูกยกเลิก ดังนั้นคุณต้องการป้องกันไม่ให้ผู้ใช้แตะปุ่ม! ทั้งหมดนี้เป็นเพียงเรื่องของการปิดใช้ปุ่ม UIAlertAction ของคุณ หากปิดใช้การแจ้งเตือน ผู้ใช้จะไม่สามารถแตะเพื่อปิดได้

หากต้องการรวมสิ่งนี้เข้ากับการตรวจสอบฟิลด์ข้อความ ให้ใช้วิธีการมอบหมายฟิลด์ข้อความหรือวิธีการดำเนินการ (กำหนดค่าไว้ในตัวจัดการการกำหนดค่าของฟิลด์ข้อความเมื่อคุณสร้างขึ้น) เพื่อเปิด/ปิดใช้งาน UIAlertActions อย่างเหมาะสม ขึ้นอยู่กับข้อความที่ป้อน (หรือยังไม่ได้) .

นี่คือตัวอย่าง เราสร้างช่องข้อความดังนี้:

alert.addTextFieldWithConfigurationHandler {
    (tf:UITextField!) in
    tf.addTarget(self, action: "textChanged:", forControlEvents: .EditingChanged)
}

เรามีการดำเนินการยกเลิกและการดำเนินการตกลง และเรานำการดำเนินการตกลงมาสู่โลกที่ปิดใช้งาน:

(alert.actions[1] as UIAlertAction).enabled = false

หลังจากนั้น ผู้ใช้ไม่สามารถแตะตกลงได้ เว้นแต่จะมีข้อความจริงอยู่ในช่องข้อความ:

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 != "")
}

แก้ไข นี่คือโค้ดด้านบนเวอร์ชันปัจจุบัน (Swift 3.0.1 และใหม่กว่า):

alert.addTextField { tf in
    tf.addTarget(self, action: #selector(self.textChanged), for: .editingChanged)
}

และ

alert.actions[1].isEnabled = false

และ

@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 != "")
}
person matt    schedule 02.09.2014
comment
comment
มีตัวอย่าง Objective-C ของสิ่งนี้หรือไม่? - person Adrian; 24.09.2015
comment
ช่างเป็นคำตอบที่งดงามและสง่างาม ขอบคุณ! ฉันเพิ่งใช้สิ่งนี้กับโปรเจ็กต์ Swift - person Adrian; 15.10.2015
comment
ขอบคุณ @AdrianB คุณทำให้วันของฉันดีขึ้น - person matt; 15.10.2015
comment
รู้สึกเหมือนว่าการรักษาตัวควบคุมการแจ้งเตือนไว้เป็นตัวแปรที่อ่อนแอนั้นมีความน่าเชื่อถือมากกว่าการเต้นครั้งต่อไปของ Responder โซลูชั่นที่ยอดเยี่ยมโดยรวม !! - person Kaan Dedeoglu; 15.04.2016
comment
หากต้องการเพิ่มสิ่งนี้ คุณสามารถสร้างการปิดและตั้งค่าให้เป็นเป้าหมายและตั้งค่าตัวเลือกที่จะเรียกใช้ ด้วยวิธีนี้คุณสามารถเก็บทุกอย่างไว้ในฟังก์ชันเดียวกันได้ - person Swinny89; 22.07.2016
comment
@ Swinny89 ฉันไม่ได้นึกภาพสิ่งที่คุณมีอยู่ในใจ คุณช่วยระบุเป็นคำตอบแยกต่างหากได้ไหม - person matt; 22.07.2016
comment
ฉันมีตัวอย่างใน Objective-C แต่ไม่ใช่ Swift ในขณะนี้ - person Swinny89; 22.07.2016
comment
เสร็จแล้วฉันจะอัปเดตคำตอบในคืนนี้พร้อมตัวอย่างที่รวดเร็ว - person Swinny89; 22.07.2016
comment
@Swinny89 เจ๋งเลย ขอบคุณนะ! ฉันหวังว่าจะได้เห็นสิ่งนั้น - person matt; 22.07.2016
comment
รหัสเวอร์ชันปัจจุบัน (ธันวาคม 2559) อยู่ที่นี่: github.com/mattneub/Programming-iOS-Book-Examples/blob/master/ - person matt; 08.12.2016
comment
รหัสเวอร์ชันปัจจุบัน (ธันวาคม 2559) ... @matt คงจะดีสำหรับคำตอบที่ดีที่จะเห็นโดยตรงที่นี่ใน StackOverflow รหัสเวอร์ชันอัปเดต - person Fmessina; 23.04.2018
comment
@Fmessina รหัสเวอร์ชันปัจจุบันแสดงโดยตรงที่นี่ในคำตอบของฉัน - person matt; 23.04.2018
comment
กำลังขว้างแอปยุติเนื่องจากข้อยกเว้นที่ไม่ได้ตรวจสอบ 'NSRangeException' เหตุผล: '*** - [__NSSingleObjectArrayI objectAtIndex:]: ดัชนี 1 เกินขอบเขต [0 .. 0]' - person Pawan; 11.09.2018

ฉันได้ทำให้คำตอบของ Matt ง่ายขึ้นโดยไม่ต้องข้ามลำดับชั้นของมุมมอง นี่เป็นการถือว่าการกระทำนั้นเป็นตัวแปรที่อ่อนแอแทน นี่คือตัวอย่างการทำงานที่สมบูรณ์:

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")
}
person ullstrm    schedule 19.03.2016
comment
@ullstrm: ขอบคุณมันช่วยได้มาก - person Pawan; 11.09.2018

จากคำตอบของ @ Matt นี่คือวิธีที่ฉันทำสิ่งเดียวกันใน 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);
}
person Olie    schedule 03.11.2015

ฉันรู้ว่านี่คือ Objectiv-C แต่มันแสดงหลักการ ฉันจะอัปเดตสิ่งนี้ด้วยเวอร์ชันที่รวดเร็วในภายหลัง

คุณสามารถทำเช่นเดียวกันโดยใช้บล็อกเป็นเป้าหมาย

เพิ่มคุณสมบัติให้กับ ViewController ของคุณเพื่อให้บล็อก (การปิดเพื่อความรวดเร็ว) มีการอ้างอิงที่ชัดเจน

@property (strong, nonatomic) id textValidationBlock;

จากนั้นสร้าง AlertViewController ดังนี้:

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];
person Swinny89    schedule 22.07.2016

นี่เป็นแนวคิดเดียวกันกับคำตอบอื่น ๆ แต่ฉันต้องการวิธีการง่าย ๆ ที่แยกได้ในส่วนขยายและพร้อมใช้งานในคลาสย่อย UIViewController ใด ๆ มันแสดงการแจ้งเตือนพร้อมช่องป้อนข้อความหนึ่งช่องและปุ่มสองปุ่ม: ตกลงและยกเลิก

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)
    }
}
person algrid    schedule 23.11.2020