【问题标题】:How to update window frames on an iPad split view?如何更新 iPad 拆分视图上的窗口框架?
【发布时间】:2021-02-28 07:05:05
【问题描述】:

我正在尝试添加一个应始终显示在主窗口顶部的横幅窗口。主窗口中的任何内容都不应阻止该横幅窗口上的内容,并且横幅窗口也不应阻止主窗口的内容。以下代码在 iPhone 上运行良好,但在启用了拆分视图的 iPad 上我遇到了一些问题。

这是正常的样子

我手动设置了两个窗口的框架,当我们在拆分视图中修改可用于场景的宽度时,当场景的宽度发生变化时,这会导致问题。

如何在拆分视图中观察应用场景的可用宽度变化?

我尝试了什么:

我尝试使用 viewWillLayoutSubviews、traitCollectionDidChange 以及 UIContentContainer 协议方法,如下面的代码所示,当我更改拆分视图上应用程序的可用宽度时,这些方法都不会被调用。只有在方向改变时才会调用它们。

项目的完整代码在这里https://github.com/anirudhbandi96/WindowTest

import UIKit


class ViewController: UIViewController {
    
    let label: UILabel = {
        let label = UILabel()
        label.numberOfLines = 0
        label.font = UIFont.preferredFont(forTextStyle: .largeTitle)
        label.textAlignment = .center
        label.textColor = .white
        return label
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        view.backgroundColor = .systemGreen
        
        
        label.text = "This is the key window"
        view.addSubview(label)
        label.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            label.topAnchor.constraint(equalTo: view.topAnchor),
            label.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            label.trailingAnchor.constraint(equalTo: view.trailingAnchor)
        ])
    }
    
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        print("laying out subviews")
    }


    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        // Just added a small delay to see the addition of the banner window clearly
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2.0) {
            
            
            guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }

            // height of the Banner window
            let height: CGFloat = 100
            
            guard let window = self.view.window,
                  let windowScene = window.windowScene,
                  let keyWindow = windowScene.windows.first(where: { $0.isKeyWindow })
            else { return }
            
            // accessing the key window and changing its frame so that the window's content is not
            // blocked by the banner window that is going to be above it
            let size = keyWindow.frame.size
            keyWindow.frame = CGRect(origin: CGPoint(x: 0, y: height), size: CGSize(width: size.width, height: size.height - height))
            
            // Creating a banner window
            let bannerWindow = UIWindow(windowScene: windowScene)
            bannerWindow.frame = CGRect(origin: .zero, size: CGSize(width: size.width, height: height))
            bannerWindow.isHidden = false
            
            // Creating a banner view and adding it to the banner window
            let bannerView = UIView(frame: .zero)
            bannerView.backgroundColor = .systemPink
            bannerView.translatesAutoresizingMaskIntoConstraints = false
            
            bannerWindow.addSubview(bannerView)
            bannerWindow.windowLevel = keyWindow.windowLevel + 1
            NSLayoutConstraint.activate([
                bannerView.leadingAnchor.constraint(equalTo: bannerWindow.leadingAnchor),
                bannerView.trailingAnchor.constraint(equalTo: bannerWindow.trailingAnchor),
                bannerView.heightAnchor.constraint(equalToConstant: height),
                bannerView.bottomAnchor.constraint(equalTo: bannerWindow.bottomAnchor),
            ])
            
            // Keeping a reference to the banner window to prevent it from being deallocated
            appDelegate.bannerWindow = bannerWindow
        }
      
    }
    
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        print("Trait collection changed")
    }
    
    override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
        super.willTransition(to: newCollection, with: coordinator)
        print("will transition to new collection")
    }
    
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        print("will transtion to size: \(size)")
    }
}

启用分屏后,它仍然使用之前为全屏设置的帧,这是有意义的。

【问题讨论】:

    标签: ios swift ipad uikit ipados


    【解决方案1】:
     override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
    

    此方法是在视图大小更改时进行更改的正确位置。尝试放置断点,只要您期望它就会被调用。

    Apple 文档:https://developer.apple.com/documentation/uikit/uicontentcontainer/1621466-viewwilltransition

    【讨论】:

    • 我确实尝试过这个,当我在拆分视图上调整场景大小时,那个方法从未被调用过。您在我附加的项目链接上尝试过吗?
    • 如果我没有修改关键窗口的框架,只是在其顶部添加了新的横幅窗口,我确实看到 viewWillTransition 以正确的场景大小但使用关键的框架被调用手动设置的窗口永远不会发生
    猜你喜欢
    • 2019-03-05
    • 2020-12-04
    • 1970-01-01
    • 1970-01-01
    • 2014-01-24
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多