pmusolino / PMAlertController

PMAlertController is a great and customizable alert that can substitute UIAlertController
MIT License
2.53k stars 186 forks source link

How to show buttons horizontally? #77

Closed anonrig closed 5 years ago

anonrig commented 5 years ago

Hey!

I'm trying to setup the buttons in a horizontal manner. Since I've 2 buttons. But I couldn't make them horizontally aligned. Any suggestions?

extension FavoritesViewController {
    func showAddUser() {
        let alertVC = PMAlertController(title: "Add friend", description: "Please write down your friends username", image: nil, style: .alert)

        alertVC.addTextField { (textField) in
            textField?.placeholder = "Username..."
            textField?.autocorrectionType = .no
            textField?.autocapitalizationType = .none
        }

        alertVC.addAction(PMAlertAction(title: "Cancel", style: .cancel, action: { () in

        }))

        alertVC.addAction(PMAlertAction(title: "Add", style: .default, action: { () in

        }))

        self.present(alertVC, animated: true, completion: nil)
    }
}
pmusolino commented 5 years ago

Hi there. Really simple. Access to the stack view of alertVC and change the axis (vertical or horizontal) 👍

anonrig commented 5 years ago

I think you misunderstood my problem.

Since buttons and the textfield are on the same stack view, if you change the axis to horizontal every element will be in the same line. That's not the desired outcome. Textfield should be in a single line and buttons should be horizontal.

pmusolino commented 5 years ago

Sorry, I had not noticed that you also have a text field inside. In this case, you can't change the alignment for single components, because every component (text fields and buttons) is inside the same stack view.

Nexmind commented 5 years ago

Hi there !

Maybe it's a little late for you, but I was facing the same problem so I create an extension to make this possible :-)

extension PMAlertController {
    static func initWithTextFieldValidation(title: String,
                                            description: String,
                                            textField: UITextField,
                                            confirmButtonTitle: String,
                                            cancelButtonTitle: String,
                                            confirmButtonAction: ((PMAlertController) -> Void)? = nil,
                                            cancelButtonAction: ((PMAlertController) -> Void)? = nil) -> PMAlertController {

        // Init the alert
        let passwordAlert = PMAlertController(title: title, description: description, image: nil, style: .alert)
        passwordAlert.gravityDismissAnimation = false

        // Create the first fieldStack with the textField and set some insets on side
        let fieldStack = UIStackView(arrangedSubviews: [textField])
        fieldStack.layoutMargins = UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 8)

        // Init actions
        let cancelAction = PMAlertAction(title: cancelButtonTitle, style: .cancel, action: { () -> Void in
            if let action = cancelButtonAction {
                action(passwordAlert)
            } else {
                passwordAlert.dismiss(animated: true, completion: nil)
            }
        })
        let confirmAction = PMAlertAction(title: confirmButtonTitle, style: .default, action: { () in
            confirmButtonAction?(passwordAlert)
        })

        // Create second Stack with actions and set his axis to horizontal
        let buttonsStack = UIStackView(arrangedSubviews: [cancelAction, confirmAction])
        buttonsStack.axis = .horizontal

        // Add constraint to be sure two buttons have the same width
        buttonsStack.addConstraint(NSLayoutConstraint(item: cancelAction, attribute: .width, relatedBy: .equal, toItem: confirmAction, attribute: .width, multiplier: 1, constant: 0))

        // set the alert's StackView axis to vertical and add stacks
        passwordAlert.alertActionStackView.axis = .vertical
        passwordAlert.alertActionStackView.addArrangedSubview(fieldStack)
        passwordAlert.alertActionStackView.addArrangedSubview(buttonsStack)

        passwordAlert.alertActionStackViewHeightConstraint.constant = 62 * CGFloat(passwordAlert.alertActionStackView.arrangedSubviews.count)

        return passwordAlert
    }
}

And here is the way to use it

let passwordField = UITextField()
        passwordField.font = UIFont.preferredFont(forTextStyle: .body)
        passwordField.isSecureTextEntry = true
        passwordField.textColor = UIColor.bodyGray
        passwordField.placeholder = "Mot de passe"
        passwordField.textAlignment = .center

        let fieldAlert = PMAlertController.initWithTextFieldValidation(title: "Connexion", description: "Entrez votre mot de passe", textField: passwordField, confirmButtonTitle: "Confirmer", cancelButtonTitle: "Annuler",
            confirmButtonAction: { alert in
                //TODO CONFIRM BUTTON
            },
            cancelButtonAction: { alert in
                alert.dismiss(animated: true, completion: nil)
            })

        self.present(fieldAlert, animated: true, completion: nil)

Hope this can help !

And thank for this very nice lib ! It's just missing this case ! :-)

olliekav commented 4 years ago

You could also add the textfield as subview of the contentStackView

let textField = TextField(frame: CGRect(x: 0, y: 0, width: 230, height: 40))
textField.placeholder = "Enter your email address"
textField.backgroundColor = ColorCompatibility.lightBackground
textField.layer.cornerRadius = 8
textField.font = UIFont.systemFont(ofSize: 15)
textField.keyboardType = UIKeyboardType.emailAddress
textField.autocapitalizationType = .none
textField.accessibilityIdentifier = "forgotPasswordInput"
textField.addTarget(self, action: #selector(self.alertTextFieldDidChange(field:)), for: UIControl.Event.editingChanged)
alert.alertContentStackView.addArrangedSubview(textField)