使用多个按钮自定义警报视图

时间:2018-12-20 03:48:37

标签: swift uibutton closures swift4

我正在设计一个自定义的通用警报视图,如下所示:

警报视图截屏

Screen Shot

但是,此视图中的2个按钮始终执行相同的操作。

它始终对两个按钮执行下面的第二行代码。

optionAlertVC.btn_ok.actionHandle(controlEvents: .touchUpInside, ForAction: ok)
optionAlertVC.btn_cancel.actionHandle(controlEvents: .touchUpInside, ForAction: cancel)

显示一些代码来帮助我解决此问题。

ViewController:

func logout() {
    AlertManager.shared.showAlertWithTwoOptions(viewController: self, message: "Confirm to logout?", okTitle: "Log out", dismissTitle: "Cancel", ok: {
        self.gotoLogin()
    }, cancel: {
        //nothing to do
    }, title: "Logout")
}

AlertManager:

typealias ok = () -> Void
typealias cancel = () -> Void
func showAlertWithTwoOptions(viewController: UIViewController, message: String, okTitle: String, dismissTitle:String, ok: @escaping ok , cancel: @escaping cancel, title:String? = nil) {
    guard let optionAlertVC = Bundle.main.loadNibNamed("AlertView", owner: nil, options: nil)?[1] as? OptionAlertVC else {
        print("error in loading error alert")
        return
    }
    optionAlertVC.lbl_title.text = title ?? "Warning"
    optionAlertVC.lbl_message.text = message
    optionAlertVC.iv_icon.image = UIImage(named: "icon_warning")
    optionAlertVC.btn_ok.backgroundColor = UIColor.MyTheme.greenSuccess
    optionAlertVC.btn_ok.setTitle(okTitle, for: .normal)
    optionAlertVC.btn_ok.titleLabel!.adjustsFontSizeToFitWidth = true
    optionAlertVC.btn_cancel.backgroundColor = UIColor.MyTheme.redWarning
    optionAlertVC.btn_cancel.setTitle(dismissTitle, for: .normal)
    optionAlertVC.btn_cancel.titleLabel!.adjustsFontSizeToFitWidth = true
    optionAlertVC.btn_cancel.titleLabel?.numberOfLines = 1

    optionAlertVC.btn_ok.actionHandle(controlEvents: .touchUpInside, ForAction: ok)
    optionAlertVC.btn_cancel.actionHandle(controlEvents: .touchUpInside, ForAction: cancel)

    viewController.present(optionAlertVC, animated: true, completion: nil)
}

UIButtonExtension:

extension UIButton {
    fileprivate func actionHandleBlock(action:(() -> Void)? = nil) {
        struct __ {
            static var action :(() -> Void)?
        }
        if action != nil {
            __.action = action
        } else {
            __.action?()
        }
    }

    @objc private func triggerActionHandleBlock() {
        self.actionHandleBlock()
    }

    func actionHandle(controlEvents control :UIControl.Event, ForAction action:@escaping () -> Void) {
        self.actionHandleBlock(action: action)
        self.addTarget(self, action: #selector(UIButton.triggerActionHandleBlock), for: control)
    }
}

1 个答案:

答案 0 :(得分:1)

首先,您不应以这种方式处理button触摸。其次,您对struct的命名不正确。如果我不得不对struct说些什么,那么我该如何命名,以便您知道我在谈论那个struct

涉及到实际问题,当您使用static处理某些内容时,这变得有些棘手。当您在static上声明action变量static var action :(() -> Void)?(即struct ___)时,无论您有多少个按钮,它都会始终调用最新的按钮回调(即, closure),因为它不是一个array,它可以保留所有按钮的回调操作,它只是一个变量,因此它将继续用最新的button覆盖以前的回调。我相信您应该删除UIButton的扩展实现,因为它将继续引起不必要的问题。

实际上,您无需执行任何其他操作即可处理UIButton触摸。只需为每个按钮声明一个单独的方法,并在添加目标时将其告知按钮,如下所示,

class OptionAlertVC: UIViewController {

    var btn_ok: UIButton!
    var btn_cancel: UIButton!

    public var okCallback: (() -> Void)?
    public var cancelCallback: (() -> Void)?

    override func viewDidLoad() {
        super.viewDidLoad()

        btn_ok.addTarget(self, action: #selector(okAction), for: .touchUpInside)
        btn_cancel.addTarget(self, action: #selector(cancelAction), for: .touchUpInside)
    }

    @objc func okAction() {
        okCallback?()
    }

    @objc func cancelAction() {
        cancelCallback?()
    }
}

现在,在showAlertWithTwoOptions中,您可以删除以下几行,

optionAlertVC.btn_ok.actionHandle(controlEvents: .touchUpInside, ForAction: ok)
optionAlertVC.btn_cancel.actionHandle(controlEvents: .touchUpInside, ForAction: cancel)

相反,将回调设置为此,

optionAlertVC.okCallback = ok
optionAlertVC.cancelCallback = cancel