swiftuitextfieldalerttoastuialertcontroller

Can I present a toast when alert is also presented?


Do you know if it's possible to present a toast message while alert is presented?

More specific, the alert contains a textfield and I want to present a toast with error message when textfield's value is over Integer's max value. So, when user gives me an incorrect value, I want to inform the user before he/she presses the alert button.

Can you help me?


Solution

  • There is no such a thing as toast in native UIKit components!

    So you can either use another Alert on top of the previous one:

    class MainViewController: UIViewController {
        @IBOutlet weak var button: UIButton!
        var alert: UIAlertController!
    
        @IBAction func buttonDidTouch() {
            alert = UIAlertController(title: "Authentication", message: "Choose a username and password", preferredStyle: .alert)
    
            alert.addTextField { textfield in
                textfield.placeholder = "Username"
                textfield.addTarget(self, action: #selector(self.changeUsername), for: .editingChanged)
            }
            alert.addTextField() { $0.placeholder = "Password" }
            alert.addAction(.init(title: "Register", style: .default))
            present(alert, animated: true)
        }
    
        @objc func changeUsername(sender: UITextField) {
            let text = sender.text!
            guard text.count > 5 else { return }
            sender.text = String(text.prefix(5))
    
            let toast = UIAlertController(title: "Invalid username", message: "The username should not be longer than 5 letters", preferredStyle: .alert)
            toast.addAction(.init(title: "Ok", style: .cancel))
    
            alert.present(toast, animated: true)
        }
    }
    

    Note: You may want to get rid of all !s and make them safe as you wish


    Or create a new window with a level more than the alert like the statusBar (or using libraries like this) and present it on top of the current window to achieve something like this:

    SM Demo

    Note: window management is a large topic and beyond the scope of this question. I suggest you to start with simple approaches and then go for tough ones. You can start with this:

    class MainViewController: UIViewController {
        @IBOutlet weak var button: UIButton!
    
        lazy var window: UIWindow = {
            let w = UIWindow(windowScene: view.window!.windowScene!)
            w.windowLevel = .statusBar
            w.backgroundColor = .green.withAlphaComponent(0.7)
            return w
        }()
    
        @IBAction func buttonDidTouch() {
            window.makeKeyAndVisible()
        }
    }