Swift Custom UIAlertView

Я пытаюсь сделать всплывающее окно подтверждения удаления. Потому что дизайн, который я хочу, сильно отличается от стиля типичного UIAlertView всплывающее окно, я решил создать кастом ConfirmationViewController что я бы вызвать всплывающее окно.

Вот какой типичный UIAlertView похоже:

И вот как я хочу, чтобы мой был похож:

Вот как я сейчас делаю свой заказ ConfirmationViewController неожиданно возникнуть:

let confirmationViewController = ConfirmationViewController()
confirmationViewController.delegate = self
confirmationViewController.setTitleLabel("Are you sure you want to remove \(firstName)?")
confirmationViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
confirmationViewController.preferredContentSize = CGSizeMake(230, 130)

let popoverConfirmationViewController = confirmationViewController.popoverPresentationController
popoverConfirmationViewController?.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
popoverConfirmationViewController?.delegate = self
popoverConfirmationViewController?.sourceView = self.view
popoverConfirmationViewController?.sourceRect = CGRectMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds),0,0)
presentViewController(
    confirmationViewController,
    animated: true,
    completion: nil)

И вот как я получаю уведомление, когда CANCEL или же REMOVE кнопка нажата:

extension UserProfileTableViewController: ConfirmationViewControllerDelegate {
    func cancelButtonPressed() {
        print("Cancel button pressed")
    }

    func confirmationButtonPressed(objectToDelete: AnyObject?) {
        print("Delete button pressed")
    }
}

Тем не менее, что мне нравится в использовании UIAlertView заключается в том, что я могу жестко кодировать действие, которое я хочу выполнить при нажатии определенной кнопки, например:

let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .Alert)

let cancelAction = UIAlertAction(title: "Cancel", style: .Default, handler: {(ACTION) in
    print("Perform cancel action")
})

let deleteAction = UIAlertAction(title: "Remove", style: .Destructive, handler: {(ACTION) in
    print("Perform delete action")
})

alertController.addAction(cancelAction)
alertController.addAction(deleteAction)

presentViewController(alertController, animated: true, completion: nil)

Итак, мой вопрос, как я могу создать обработчик завершения (встроенный) таким образом, чтобы при CANCEL или же REMOVE кнопка нажата с моим кастомом ConfirmationViewController Я могу запустить действие, как я показал, как это делается с UIAlertControllerвместо нынешнего способа я делаю это с делегированием?

Является ли ответ просто создать пользовательское всплывающее окно, которое я ищу с UIAlertController? И если так, как я могу настроить его в той степени, в которой я ищу?

Заранее спасибо и извините за длинный пост:)

PS вот что мое ConfirmationViewController а также ConfirmationViewControllerDelegate выглядит как:

protocol ConfirmationViewControllerDelegate {
    func cancelButtonPressed()
    func confirmationButtonPressed(objectToDelete: AnyObject?)
}

class ConfirmationViewController: UIViewController {
    var didSetupConstraints = false

    let titleLabel = UILabel.newAutoLayoutView()
    let buttonContainer = UIView.newAutoLayoutView()
    let cancelButton = ButtonWithPressingEffect.newAutoLayoutView()
    let confirmationButton = ButtonWithPressingEffect.newAutoLayoutView()

    var delegate: ConfirmationViewControllerDelegate?

    var objectToDelete: AnyObject?

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor.whiteColor()

        titleLabel.numberOfLines = 0

        cancelButton.backgroundColor = UIColor.colorFromCode(0x7f7f7f)
        cancelButton.layer.cornerRadius = 5
        cancelButton.setAttributedTitle(NSMutableAttributedString(
            string: "CANCEL",
            attributes: [
                NSFontAttributeName: UIFont(name: "AvenirNextLTPro-Demi", size: 12)!,
                NSForegroundColorAttributeName: UIColor.whiteColor(),
                NSKernAttributeName: 0.2
            ]
        ), forState: UIControlState.Normal)
        cancelButton.addTarget(self, action: #selector(cancelButtonPressed), forControlEvents: .TouchUpInside)

        confirmationButton.backgroundColor = Application.redColor
        confirmationButton.layer.cornerRadius = 5
        confirmationButton.setAttributedTitle(NSMutableAttributedString(
            string: "REMOVE",
            attributes: [
                NSFontAttributeName: UIFont(name: "AvenirNextLTPro-Demi", size: 12)!,
                NSForegroundColorAttributeName: UIColor.whiteColor(),
                NSKernAttributeName: 0.2
            ]
        ), forState: UIControlState.Normal)
        confirmationButton.addTarget(self, action: #selector(confirmationButtonPresssed), forControlEvents: .TouchUpInside)

        view.addSubview(titleLabel)
        view.addSubview(buttonContainer)
        buttonContainer.addSubview(cancelButton)
        buttonContainer.addSubview(confirmationButton)
        updateViewConstraints()
    }

    func cancelButtonPressed() {
        delegate?.cancelButtonPressed()
        dismissViewControllerAnimated(false, completion: nil)
    }

    func confirmationButtonPresssed() {
        delegate?.confirmationButtonPressed(objectToDelete)
        dismissViewControllerAnimated(false, completion: nil)
    }

    func setTitleLabel(text: String) {
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = NSTextAlignment.Center
        paragraphStyle.lineSpacing = 4.5
        titleLabel.attributedText = NSMutableAttributedString(
            string: text,
            attributes: [
                NSFontAttributeName: UIFont(name: "AvenirNextLTPro-Regular", size: 14)!,
                NSForegroundColorAttributeName: UIColor.colorFromCode(0x151515),
                NSKernAttributeName: 0.5,
                NSParagraphStyleAttributeName: paragraphStyle
            ]
        )
    }

    override func updateViewConstraints() {
        if !didSetupConstraints {
            titleLabel.autoPinEdgesToSuperviewEdgesWithInsets(UIEdgeInsets(top: 10, left: 10, bottom: 0, right: 10), excludingEdge: .Bottom)
            titleLabel.autoAlignAxisToSuperviewAxis(.Vertical)

            buttonContainer.autoPinEdge(.Top, toEdge: .Bottom, ofView: titleLabel, withOffset: 3)
            buttonContainer.autoAlignAxisToSuperviewAxis(.Vertical)
            buttonContainer.autoPinEdgeToSuperviewEdge(.Bottom, withInset: 10)

            let contactViews: NSArray = [cancelButton, confirmationButton]
            contactViews.autoDistributeViewsAlongAxis(.Horizontal, alignedTo: .Horizontal, withFixedSpacing: 7, insetSpacing: true, matchedSizes: false)

            cancelButton.autoPinEdgeToSuperviewEdge(.Top)
            cancelButton.autoPinEdgeToSuperviewEdge(.Bottom)
            cancelButton.autoSetDimensionsToSize(CGSize(width: 100, height: 50))

            confirmationButton.autoPinEdgeToSuperviewEdge(.Top)
            confirmationButton.autoPinEdgeToSuperviewEdge(.Bottom)
            confirmationButton.autoSetDimensionsToSize(CGSize(width: 100, height: 50))

            didSetupConstraints = true
        }

        super.updateViewConstraints()
    }
}

1 ответ

Решение

Что-то вроде следующего должно позволить это. Обратите внимание, что можно сделать несколько улучшений. Например, вы можете использовать универсальный объект для удаляемого объекта вместо AnyObject. Вам также не обязательно передавать его, если вы в любом случае вставляете закрывающую строку, чтобы вы могли просто удалить ее.

Вы также можете сделать кнопки более пригодными для повторного использования, а не жестко программировать для отмены и удаления, но теперь мы не в теме:)

class ConfirmViewController : UIViewController {
    var onCancel : (() -> Void)?
    var onConfirm : ((AnyObject?) -> Void)?

    var objectToDelete : AnyObject?

    func cancelButtonPressed() {
        // defered to ensure it is performed no matter what code path is taken
        defer {
            dismissViewControllerAnimated(false, completion: nil)
        }

        let onCancel = self.onCancel
        // deliberately set to nil just in case there is a self reference
        self.onCancel = nil
        guard let block = onCancel else { return }
        block()
    }

    func confirmationButtonPresssed() {
        // defered to ensure it is performed no matter what code path is taken
        defer {
            dismissViewControllerAnimated(false, completion: nil)
        }
        let onConfirm = self.onConfirm
        // deliberately set to nil just in case there is a self reference
        self.onConfirm = nil
        guard let block = onConfirm else { return }
        block(self.objectToDelete)
    }
}

let confirm = ConfirmViewController()
confirm.objectToDelete = NSObject()
confirm.onCancel = {
    // perform some action here
}
confirm.onConfirm = { objectToDelete in
    // delete your object here
}
Другие вопросы по тегам