首页 > 解决方案 > 自定义警报显示在空窗口而不是以前的 viewController

问题描述

如您所见,我将演示样式设置为.overCurrentContext.

 extension SingleQuestionViewController: AddResponseDelegate {

  func save(response text: String, questionID: Int) {
    questionsWrapper.add(newResponse: text, questionID: questionID) { [weak self] successful in
        if successful {
            self?.responseTV?.safelyReload()
        } else {
            DispatchQueue.main.async {
                let alertViewController = AlertViewController<Any>()
                alertViewController.modalPresentationStyle = .overCurrentContext
                let contentModel = RegularContentsModel(title: "controllerTitle", message: "message")

                let authorizeButtonModel = SimpleButtonModel(title: "yes message", action: {
                    //action goes here
                })

                let doNothingButtonModel = SimpleButtonModel(title: "noMsg", action: {
                    //completion?()
                })

                alertViewController.styleRegular(regularContentsModel: contentModel,
                                                 models: [authorizeButtonModel, doNothingButtonModel])

                self?.present(alertViewController, animated: false, completion: nil)
            }
        }
    }
    questionsWrapper.goToQuestion(with: questionID)
    responseTV?.safelyReload()
  }
}

结果如下:

在此处输入图像描述

我不认为这是由于它在后台线程上造成的,因为如果我将它移动到 viewDidLoad,那么我会得到相同的结果:

    override func viewDidLoad() {
        super.viewDidLoad()
        setUpTopBar()
        setupSearchBar()
        responseTV.showsVerticalScrollIndicator = false
        setupArrows()
        responseTV.register(SimpleCell.self, forCellReuseIdentifier: SimpleCell.reuseID)
        setAccessibility()        
        let alertViewController = AlertViewController<Any>()
        alertViewController.modalPresentationStyle = .overCurrentContext
        let contentModel = RegularContentsModel(title: "controllerTitle", message: "message")

        let authorizeButtonModel = SimpleButtonModel(title: "yes message", action: {
            //action goes here
        })

        let doNothingButtonModel = SimpleButtonModel(title: "noMsg", action: {
            //completion?()
        })

        alertViewController.styleRegular(regularContentsModel: contentModel,
                                         models: [authorizeButtonModel, doNothingButtonModel])

        self.present(alertViewController, animated: false, completion: nil)
    }

这是我的自定义警报的实现。

class AlertViewController<Payload>: AkinVC {

  typealias FlagsAction = ([ReportFlag], Payload) -> Void

  enum AlertStyle<Payload> {
    case flag(FlagsAction)
  }

  let innerWholeAlertContainer = UIView() 
  let outerWholeAlertContainer = UIView()


  let buttonStack = AlertButtonsStack()
  var payload: Payload?
  let transitionDuration: TimeInterval = 0.11
  let containerWidth: CGFloat = 300

  private var contentsView: UIView! {
    didSet {
        innerWholeAlertContainer.addSubview(contentsView)
        contentsView.constraints(firstHorizontal: .distanceToLeading(innerWholeAlertContainer.leadingAnchor, 0),
                                 secondHorizontal: .distanceToTrailing(innerWholeAlertContainer.trailingAnchor, 0),
                                 vertical: .distanceToTop(innerWholeAlertContainer.topAnchor, 0),
                                 secondVertical: .distanceToBottom(buttonStack.topAnchor, 0))
      }
  }

  func styleNoButtons(regularContentsModel: RegularContentsModel) {
    initialSetup()
    let alertContentView = RegularContentsView()
    alertContentView.model = regularContentsModel.forContainer(width: containerWidth)
    contentsView = alertContentView
    setButtonConstraints()
  }

  func styleAsFlagView(flagsAction: @escaping FlagsAction) {

    initialSetup()
    let stackView = FlagsStackView()
    stackView.flagItemViews = [FlagItemView](ReportFlag.allCases)
    contentsView = stackView

    buttonStack.buttonModels(
        ButtonModel(tekt: "Report", color: .romanceRed, tektColor: .white, action: { [weak stackView] in
            guard let selectedFlags = stackView?.flagItemViews?.selectedFlags,
                let payload = self.payload else { return }
            flagsAction(selectedFlags, payload)
            self.dismissAlert()
        }),
        ButtonModel(tekt: "Cancel", color: .white, tektColor: .black,
                    borders: BorderModel(color: UIColor.black.withAlphaComponent(0.16), width: 1, edges: [.top]),
            action: { [weak self] in
            self?.dismissAlert()
        })
    )
    setButtonConstraints()
  }

  func styleAsOkayAlert(regularContentsModel: RegularContentsModel, action: Action? = nil) {
    initialSetup()
    let alertContentView = RegularContentsView()
    alertContentView.model = regularContentsModel.forContainer(width: containerWidth)
    contentsView = alertContentView

    let okayModel = standardizeButtonsWithDismissAction(models: [SimpleButtonModel(title: "Okay, I got it.", action: action)])
    buttonStack.buttonModels(okayModel)
    setButtonConstraints()
  }

  func styleCancelAlert(regularContentsModel: RegularContentsModel, models: SimpleButtonModel...) {
    initialSetup()
    let alertContentView = RegularContentsView()
    alertContentView.model = regularContentsModel.forContainer(width: containerWidth)
    contentsView = alertContentView

    var models = models
    models.append(SimpleButtonModel(title: "Cancel"))
    let newButtonModels = standardizeButtonsWithDismissAction(models: models)
    buttonStack.buttonModels(newButtonModels)
    setButtonConstraints()
  }

func styleRegular(regularContentsModel: RegularContentsModel, models: SimpleButtonModel...) {
    self.styleRegular(regularContentsModel: regularContentsModel, models: models)
  }

  func styleRegular(regularContentsModel: RegularContentsModel, models: [SimpleButtonModel]) {
    initialSetup()

    let alertContentView = RegularContentsView()
    alertContentView.model = regularContentsModel.forContainer(width: containerWidth)
    contentsView = alertContentView

    let newButtonModels = standardizeButtonsWithDismissAction(models: models)
    buttonStack.buttonModels(newButtonModels)
    setButtonConstraints()
  }

  private func standardizeButtonsWithDismissAction(models: [SimpleButtonModel]) -> [ButtonModel] {
    var buttonModelsToAdd: [ButtonModel] = []
    let count = models.count
    for (inde, model) in models.enumerated() {
        var borders: [BorderModel] = []
        if count > 2 || count == 1 {
            borders.append(BorderModel(color: .lightGray, width: 1, edges: [.top]))
        } else if count == 2 {
            if inde == 0 {
                borders.append(BorderModel(color: .lightGray, width: 1, edges: [.top]))
            } else if inde == 1 {
                borders.append(BorderModel(color: .lightGray, width: 1, edges: [.left, .top]))
            }
        }
        buttonModelsToAdd.append(ButtonModel(tekt: model.title, color: .white, tektColor: .darkGray, borders: borders, action: {
            model.action?()
            self.dismissAlert()
        }))
    }
    return buttonModelsToAdd
  }

  func dismissAlert() {
    UIView.animate(withDuration: transitionDuration, animations: {
        self.view.alpha = 0
    }) { (completed) in
        self.safelyDissmiss(animated: false)
    }
  }


  fileprivate func initialSetup() {
    self.view.alpha = 0
    modalPresentationStyle = .currentContext
    view.backgroundColor = UIColor.black.withAlphaComponent(0.3)
    view.addSubview(outerWholeAlertContainer)
    outerWholeAlertContainer.addSubview(innerWholeAlertContainer)
    outerWholeAlertContainer.pinToEdges(innerWholeAlertContainer)
    innerWholeAlertContainer.backgroundColor = .white
    innerWholeAlertContainer.addSubview(buttonStack)
    outerWholeAlertContainer.constraints(.horizontal(.centeredHorizontallyWith(view)),
                                         .vertical(.centeredVerticallyTo(view)),
                                         .horizontal(.width(containerWidth)) )
  }

func setButtonConstraints() {
    buttonStack.constraints(.horizontal(.distanceToLeading(innerWholeAlertContainer.leadingAnchor, 0)),
                            .horizontal(.distanceToTrailing(innerWholeAlertContainer.trailingAnchor, 0)),
                            .vertical(.distanceToBottom(innerWholeAlertContainer.bottomAnchor, 0)))
  }

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    outerWholeAlertContainer.layer.applySketchShadow()
    innerWholeAlertContainer.roundCorners(constant: 15)
    UIView.animate(withDuration: transitionDuration, animations: {
        self.view.alpha = 1
    })
  }
}

以下是可视化调试器显示的内容:

在此处输入图像描述

在此处输入图像描述

标签: swift

解决方案


视图控制器:

  • 创建警报控制器;
  • 设置modalPresentationStyle.overCurrentContext; 和
  • 并调用styleRegular

但是styleRegular

  • 来电initialSetup
  • 重置modalPresentationStyle.currentContext

最后一步就是放弃你之前的.overCurrentContext设置。


推荐阅读