Swift:将自定义警报视图置于导航栏之上

Swift: Bring custom alert view over nav bar

我在我的应用程序中使用 UIView 作为警报视图,并且我想在设备未连接到互联网时将其显示为屏幕顶部的横幅。所以我的问题是这个视图出现在我的导航栏下,我怎样才能把它放在前面?我已经试过了UIApplication.shared.keyWindow!并将我的 backgroundView 作为子视图添加到其中,但这会导致其他问题。

这是我的警报视图class:我会提供所有class,但我的实现是在 show() 方法中。

import Foundation
import UIKit
import SnapKit

class ConnectionAlertView: UIView, UIGestureRecognizerDelegate {
    
    internal var backgroundView: UIView = {
        let view = UIView()
        view.backgroundColor = Theme.Color.alertLabelBackgroundColor
        view.alpha = 0
        view.layer.cornerRadius = 15
        return view
    }()
    
    internal var dismissButton: UIImageView = {
        let imageView = UIImageView()
        imageView.image = UIImage(named: "close_icon")
        imageView.layer.cornerRadius = 15
        imageView.isUserInteractionEnabled = true

        return imageView
    }()
    
    internal var descriptionTitleLabel: UILabel = {
        let label = UILabel()
        label.text = "Відсутнє підключення до Інтернету"
        label.font = Theme.Font.fontBodyLarge
        label.textColor = .white
        
        return label
    }()
    
    internal var descriptionLabel: UILabel = {
        let label = UILabel()
        label.text = "Перевірте налаштування мережі"
        label.font = Theme.Font.fontBodyMedium
        label.textColor = .white
        
        return label
    }()
    
    // MARK: - Private Methods -
    internal func layout() {
        backgroundView.addSubview(descriptionTitleLabel)
        backgroundView.addSubview(descriptionLabel)
        backgroundView.addSubview(dismissButton)
        
        descriptionTitleLabel.snp.makeConstraints { make in
            make.trailing.equalTo(backgroundView).offset(54)
            make.leading.equalTo(backgroundView).offset(16)
            make.top.equalTo(backgroundView).offset(12)
        }
        
        descriptionLabel.snp.makeConstraints { make in
            make.leading.equalTo(descriptionTitleLabel.snp.leading)
            make.top.equalTo(descriptionTitleLabel.snp.bottom).offset(4)
        }
        
        dismissButton.snp.makeConstraints { make in
            make.width.height.equalTo(30)
            make.centerY.equalTo(backgroundView)
            make.trailing.equalTo(backgroundView).offset(-16)
        }
    }
    
    internal func configure() {
        let tap = UITapGestureRecognizer(target: self, action: #selector(dismiss(sender:)))
        tap.delegate = self
        dismissButton.addGestureRecognizer(tap)
    }
    
    // MARK: - Public Methods -
    func show(viewController: UIViewController) {
        guard let targetView = viewController.view else { return }
        
        backgroundView.frame = CGRect(x: 10, y: 50, width: targetView.frame.width - 20 , height: 67)
        targetView.addSubview(targetView)
        
        layout()
        configure()
        
        // show view
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            UIView.transition(with: self.backgroundView, duration: 0.6,
                              options: .transitionCrossDissolve,
                              animations: {
                self.backgroundView.alpha = 1
            })
        }
        
        // hide view after 5 sec delay
        DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
            UIView.transition(with: self.backgroundView, duration: 1,
                              options: .transitionCrossDissolve,
                              animations: {
                self.backgroundView.alpha = 0
            })
        }
    }
    
    // MARK: - Objc Methods -
    @objc internal func dismiss(sender: UITapGestureRecognizer) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            UIView.transition(with: self.backgroundView, duration: 1,
                              options: .transitionCrossDissolve,
                              animations: {
                self.backgroundView.alpha = 0
            })
        }
    }
}

我的viewController:

class PhoneNumViewController: UIViewController {
let alert = ConnectionAlertView()
private func checkInternetConnection() {
        if !NetworkingMonitor.isConnectedToInternet {
            log.error("No internet connection!")
            alert.show(viewController: self)
        }
    }
}

由于您有一个导航控制器并且不希望将此视图直接添加到 window,我可以提供以下可行的想法。

您的 UIViewController 包含在 UINavigationController 中,因此如果您将警报添加到 UIViewController,您会在 UINavigationBar 下方注意到它。

您可以改为通过以下更改显示来自 UINavigationController 的警报。

1.

在你的 class ConnectionAlertView: UIView 中的 func show(viewController: UIViewController) 我更改了以下行:

targetView.addSubview(targetView)

targetView.addSubview(backgroundView)

这与您的问题没有直接关系,但似乎是一个错误并导致崩溃,因为您似乎想在目标视图上添加背景视图。

2. 在你的 class ViewController: UIViewController 中,当你想显示你的警报视图时,像这样传递 UINavigationController:

if let navigationController = self.navigationController
{
    alert.show(viewController: navigationController)
}

我相信这应该会给你想要的结果(图像和字体看起来不同,因为我没有这些文件,但在你这边应该可以正常工作):