Search code examples
swiftdropdownalert

How to set a dropdown menu in the Alert Controller? Swift 5


I have the following code which works very well, however I would like the second text field ("What is the priority?") to be a drop-down menu selection, of numbers 1-5, instead of allowing the user to input it.

// Create alert controller
    let alertController = UIAlertController(title: "Add New Project", message: "Begin an empty project here.", preferredStyle: .alert)

    // add textfield at index 0
    alertController.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in
        textField.placeholder = "Project Name"
    })

    // add textfield at index 1
    alertController.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in
        textField.placeholder = "What is the Priority (1-5)?"
    })

    // Alert action confirm
    let confirmAction = UIAlertAction(title: "Add Project", style: .default, handler: {(_ action: UIAlertAction) -> Void in
        print("action confirmed")
    })
    alertController.addAction(confirmAction)
    
    // Alert action cancel
    let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: {(_ action: UIAlertAction) -> Void in
        print("Cancelled")
    })
    alertController.addAction(cancelAction)

    // Present alert controller
    present(alertController, animated: true, completion: nil)

Solution

  • UIAlertController doesn't have any support for adding menus. Its public API only supports adding buttons via UIAlertAction and adding text fields.

    One workaround these limitations is to add a UIButton as the text field's rightView (or leftView). Setup the button with a menu containing 5 actions for the 5 possible values.

    alertController.addTextField(configurationHandler: {(_ textField: UITextField) -> Void in
        textField.placeholder = "Priority"
        let button = UIButton(type: .custom)
        button.setTitle("Select", for: .normal)
        button.menu = UIMenu(children: (1...5).map({ num in
            UIAction(title: String(num)) { action in
                textField.text = String(num)
            }
        }))
        button.showsMenuAsPrimaryAction = true
        textField.rightView = button
        textField.rightViewMode = .always
    })
    

    The text field is still editable but the user can select a value from the menu presented when the button is tapped.

    If desired, there are tricks to make the text field read-only while still allowing the button to work. You would need to set the text field's delegate and return false from the shouldChangeCharactersIn delegate method. You can find plenty of existing questions covering that detail.