维护添加到 KeyWindow 的自定义 UIView

Posted

技术标签:

【中文标题】维护添加到 KeyWindow 的自定义 UIView【英文标题】:Maintain custom UIView that is added to KeyWindow 【发布时间】:2019-08-30 08:22:54 【问题描述】:

我正在为我的应用开发同步功能。

我想要实现的是显示一个自定义 UIView,它将作为用户的指示器,无论用户在哪里(例如导航到仪表板、设置、个人资料页面等),同步正在进行中.短期内,它会静态地固定在应用内的某个位置。

在网上做了一些研究后,我得出结论使用keyWindow并为其添加一个子视图。

这是我的代码

override func viewDidAppear(_ animated: Bool) 
    super.viewDidAppear(animated)

    if let window = UIApplication.shared.keyWindow 
        window.windowLevel = .statusBar

        let uiView = UIView()
        uiView.backgroundColor = .green

        window.addSubview(uiView)

        uiView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            uiView.heightAnchor.constraint(equalToConstant: 150),
            uiView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 25),
            uiView.topAnchor.constraint(equalTo: view.topAnchor, constant: 150),
            uiView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.4)
        ])
    

以上代码运行良好,我可以将自定义视图附加到 keyWindow。但是,当用户导航到另一个屏幕时,添加的 customView 将消失,并且仅在用户返回上一个屏幕时显示。

有人可以指导我缺少哪一部分吗?我在哪部分做错了?

谢谢

【问题讨论】:

这取决于您希望用户交互如何工作。我会先尝试添加另一个窗口;与制作自定义警报视图相同。或者更简单的方法可能只为您工作,通过操作 layer.zPosition 来更改自定义视图的 Z 顺序。 嗨@MaticOblak,感谢您的回复。您介意就如何添加另一个窗口提供一些见解吗?我不太确定那是什么。谢谢.. :) 【参考方案1】:

根据 cmets,我添加了创建新窗口的最低要求,该窗口现在可以始终位于您的视图控制器甚至其他窗口的顶部:

class OverlayViewController: UIViewController 

    private var myWindow: UIWindow? // Our own window needs to be retained

    override func viewDidLoad() 
        super.viewDidLoad()
        view.backgroundColor = UIColor.black.withAlphaComponent(0.3)
        view.addSubview(
            let label = UILabel(frame: .zero)
            label.text = "This is an overlay."
            label.sizeToFit()
            label.center = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
            return label
        ())

        view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(onTap)))
    

    @objc private func onTap() 
        myWindow?.isHidden = true
        myWindow?.removeFromSuperview()
        myWindow = nil
        

    static func showInNewWindow() 
        let window = UIWindow(frame: UIScreen.main.bounds)
//        window.windowLevel = .alert
//        window.isUserInteractionEnabled = false
        window.rootViewController = 
            let controller = OverlayViewController() // OR UIStoryboard(name: "<#FileName#>", bundle: nil).instantiateViewController(withIdentifier: "<#Storyboard Identifier#>")
            controller.myWindow = window
            return controller
        ()

        window.makeKeyAndVisible()
           


所以这只是全代码的简单视图控制器示例,只需调用OverlayViewController.showInNewWindow() 即可在项目的任何地方使用它。视图控制器可以来自故事板。

有趣的部分是showInNewWindow,它创建了一个新窗口和这个视图控制器的一个实例,它被设置为一个根视图控制器。要显示新窗口,您只需拨打makeKeyAndVisible。要删除它,只需隐藏它并将其从超级视图中删除,就像在onTap 中所做的那样。在这种情况下,该窗口由应创建保留周期的视图控制器引用。似乎这是强制性的。这也意味着我们需要在通过调用myWindow = nil 关闭窗口后进行一些清理。

还有一些可能的设置,例如您可以禁用用户交互并允许用户仍然使用此窗口下方的窗口 (window.isUserInteractionEnabled = false)。您可以设置窗口的级别,以显示它的显示位置(window.windowLevel = .alert)。您可以使用这些值进行一些操作。设置哪个取决于您希望窗口的级别。

【讨论】:

非常感谢您的详细解释!真的很感激 Btw Matic,makeKeyAndVisible() 是否等同于 isHidden = false? @Alvin 我不这么认为。我认为它在后面做了一些额外的工作,比如将自己注册为关键窗口,我认为这是应用程序的一个属性。我相信根据文档,必须调用它。 知道了。非常感谢 Matic

以上是关于维护添加到 KeyWindow 的自定义 UIView的主要内容,如果未能解决你的问题,请参考以下文章

如何在添加到 keyWindow 的视图上方显示模式?

UIGesture 返回 UIImageView 而不是自定义视图

KeyWindow添加subView,前面没有显示

UIAlertViews、UIActionSheets 和 keyWindow 问题

[UIApplication sharedApplication].keyWindow 添加视图无效,解决方案。

Qt - 我自己的自定义对象的 QListView