123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- import UIKit
- public final class AlertView: UIView {
-
- public static var `default`: AlertView {
- return AlertView()
- }
-
- private typealias ItemAction = ((AlertItem) -> Void)
-
- private var confirmAction: AlertAction?
- private var cancelAction: AlertAction?
-
- public var cancelItem: AlertItem = {
- let item = AlertItem(type: .custom)
- item.backgroundColor = UIColor(r: 214, g: 214, b: 214)
- item.setTitleColor(UIColor(r: 51, g: 51, b: 51), for: .normal)
-
- return item
- }()
-
- public var confirmItem: AlertItem = {
- let item = AlertItem(type: .custom)
- item.backgroundColor = UIColor(r: 129, g: 209, b: 53)
- item.setTitleColor(UIColor.white, for: .normal)
-
- return item
- }()
-
- public var titleLabel: UILabel = {
- var label = UILabel()
- label.numberOfLines = 0
- label.textAlignment = .left
- label.backgroundColor = UIColor.white
- label.font = UIFont.systemFont(ofSize: 17)
- label.textColor = UIColor(r: 53, g: 53, b: 53)
-
- return label
- }()
-
- public var messageLabel: UILabel = {
- var label = UILabel()
- label.numberOfLines = 0
- label.textAlignment = .left
- label.backgroundColor = UIColor.white
- label.font = UIFont.systemFont(ofSize: 15)
- label.textColor = UIColor(r: 153, g: 153, b: 153)
-
- return label
- }()
-
- public var contentView: UIView?
-
- private var viewNotReady = true
- private var bottomView: UIView?
- private var topView: UIView?
-
- var title: String = "" {
- didSet {
- titleLabel.text = title
- }
- }
- var message: String = "" {
- didSet {
- messageLabel.text = message
- }
- }
-
- override public func didMoveToWindow() {
- super.didMoveToWindow()
- guard viewNotReady else { return }
- constructViewHierarchy()
- activateConstraints()
- installTarget()
- backgroundColor = UIColor.white
- viewNotReady = false
- }
-
- private func constructViewHierarchy() {
- if !title.isEmpty { addSubview(titleLabel) }
- if !message.isEmpty { addSubview(messageLabel) }
- if cancelAction != nil { addSubview(cancelItem) }
- if confirmAction != nil { addSubview(confirmItem) }
- if let contentView = contentView { addSubview(contentView) }
- }
-
- private func activateConstraints() {
- activateConstraintsItems()
- activateConstraintsLabels()
- activateConstraintsContentView()
- activateConstraintsRootView()
- }
-
- func addAlertAction(_ action: AlertAction) {
- switch action.style {
- case .default:
- confirmAction = action
- case .cancel:
- cancelAction = action
- case let .custom(item):
- confirmAction = action
- confirmItem = item
- }
- }
-
- private func installTarget() {
- if cancelAction != nil {
- cancelItem.addTarget(self, action: #selector(cancelAction(btn:)), for: .touchDown)
- }
-
- if confirmAction != nil {
- confirmItem.addTarget(self, action: #selector(confirmAction(btn:)), for: .touchDown)
- }
- }
-
- @objc private func confirmAction(btn: UIButton) {
- confirmAction?.handler?(confirmItem)
-
- dismissSuperViewController()
- }
-
- @objc private func cancelAction(btn: UIButton) {
- cancelAction?.handler?(cancelItem)
-
- dismissSuperViewController()
- }
-
- private func dismissSuperViewController() {
- guard let vc = getSuperViewController() else { return }
- vc.dismissController()
- }
- }
- fileprivate extension AlertView {
- func activateConstraintsRootView() {
- guard let v = superview else { return }
- translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- centerYAnchor.constraint(equalTo: v.centerYAnchor),
- centerXAnchor.constraint(equalTo: v.centerXAnchor),
- leadingAnchor.constraint(equalTo: v.leadingAnchor, constant: 40),
- trailingAnchor.constraint(equalTo: v.trailingAnchor, constant: -40),
- ])
-
- if #available(iOS 11, *) {
- directionalLayoutMargins = NSDirectionalEdgeInsets(top: 10, leading: 16, bottom: 0, trailing: 16)
- } else {
- layoutMargins = UIEdgeInsets(top: 10, left: 16, bottom: 0, right: 16)
- }
- guard let topView = topView else { return }
- NSLayoutConstraint.activate([
- topView.bottomAnchor.constraint(equalTo: bottomView?.topAnchor ?? bottomAnchor, constant: -12)
- ])
- }
-
- func activateConstraintsContentView() {
- guard let contentView = contentView else { return }
- contentView.translatesAutoresizingMaskIntoConstraints = false
-
- NSLayoutConstraint.activate([
- contentView.leadingAnchor.constraint(equalTo: leadingAnchor),
- contentView.trailingAnchor.constraint(equalTo: trailingAnchor),
- contentView.topAnchor.constraint(equalTo: topView?.bottomAnchor ?? topAnchor),
- contentView.bottomAnchor.constraint(equalTo: bottomView?.bottomAnchor ?? bottomAnchor)
- ])
-
- bottomView = contentView
- }
-
- func activateConstraintsItems() {
- let (alertActions, items) = getActionsAndItems()
- guard !alertActions.isEmpty, let width = superview?.bounds.width else { return }
-
-
-
- let spacing: CGFloat = 80 + 32
- let itemSpacing: CGFloat = CGFloat((items.count - 1) * 6)
- let w = (width - spacing - itemSpacing) / CGFloat(items.count)
-
- var last: AlertItem? = nil
- var leading: CGFloat = 0
- for (action, item) in zip(alertActions, items) {
- item.translatesAutoresizingMaskIntoConstraints = false
- item.setTitle(action.title, for: .normal)
-
- NSLayoutConstraint.activate([
- item.widthAnchor.constraint(equalToConstant: w),
- item.heightAnchor.constraint(equalToConstant: 36),
- item.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -14),
- item.leadingAnchor.constraint(equalTo: last?.trailingAnchor ?? layoutMarginsGuide.leadingAnchor, constant: leading)
- ])
-
- leading = 6
- last = item
- }
- bottomView = last
- }
-
- func activateConstraintsLabels() {
- var labels: [UILabel] = []
- if !title.isEmpty { labels.append(titleLabel) }
- if !message.isEmpty { labels.append(messageLabel) }
- if labels.isEmpty { return }
-
- var last: UILabel? = nil
-
- for label in labels {
- label.translatesAutoresizingMaskIntoConstraints = false
- NSLayoutConstraint.activate([
- label.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
- label.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
- label.topAnchor.constraint(equalTo: last?.bottomAnchor ?? layoutMarginsGuide.topAnchor, constant: 6),
- ])
-
- last = label
- }
-
- topView = last
- }
- }
- fileprivate extension AlertView {
- func getActionsAndItems() -> ([AlertAction], [AlertItem]) {
- let alertActions = [cancelAction, confirmAction].compactMap { $0 }
- let items = alertActions.map { (action) -> AlertItem in
- switch action.style {
- case .cancel:
- return cancelItem
- case .default, .custom:
- return confirmItem
- }
- }
- return (alertActions, items)
- }
- }
|