Swift iOS -How to Switch / Toggle between two UIWindows and make either the keyWindow
Swift iOS -How to Switch / Toggle between two UIWindows and make either the keyWindow
I created an additional UIWindow that will get presented on top of the main window. The user presses a button and it transitions over the main window. The user can minimize the additional window and it will sit above the tabBar like it the picture below. They can enlarge it to cover the main window or dismiss it and it gets destroyed. It works fine.
I also created a custom action sheet that launches from the bottom of the screen. If the additional window completely covers the main window and the action sheet is launched, it will launch perfectly inside the additional window. If the additional window isn't on the screen it launches perfectly inside the main window.
The problem is if the additional window is minimized on screen and I want to launch the action sheet from the main window, the action sheet launches inside the additional window instead, it cannot distinguish between the two. I opened up the 3D visualizer and it showed that the main window was off
and the additional window was on
.
off
on
How can I distinguish between both windows when displaying the custom action sheet?
Btw if both windows are present and the action sheet is launched from the main window I hide the additional window. I also looked at other answers and they said to use UIApplication.shared.keyWindow.addSubview
which I'm already doing.
UIApplication.shared.keyWindow.addSubview
CustomActionSheet Class:
var collectionView: UICollectionView!
var deltaY: CGFloat!
let height: CGFloat = 200 // 4 cells x 50 pts each
func displayActionSheet(){
if let window = UIApplication.shared.keyWindow {
// collectionView initialized...
window.addSubview(collectionView)
deltaY = window.frame.height - height
collectionView.frame = CGRect(x: 0, y: window.frame.height, width: window.frame.width, height: height)
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [.curveEaseOut], animations: {
self.collectionView.frame = CGRect(x: 0, y: deltaY, width: self.collectionView.frame.width, height: self.collectionView.frame.height)
}
}
}
MainView Class:
@IBAction func mainWindowActionSheetButton(_ sender: UIButton) {
let customActionSheet = CustomActionSheet()
customActionSheet.displayActionSheet()
}
AdditionalWindow Class:
let myVC = MyController()
var nav: UINavigationController?
var window: UIWindow!
var maximized = true
override init() {
super.init()
window = UIWindow()
window.backgroundColor = .clear
window.windowLevel = UIWindowLevelStatusBar
nav = UINavigationController(rootViewController: myVC)
window.rootViewController = nav
window?.isHidden = false
window?.makeKeyAndVisible()
}
func maximizeOrMinimizeWindow() {
if maximized {
// show this full screen
} else {
// show this window minimized like in the picture
}
}
AnotherController Class that has the button that also launches the action sheet:
@IBAction func additionalWindowActionSheetButton(_ sender: UIButton) {
let customActionSheet = CustomActionSheet()
customActionSheet.displayActionSheet()
}
@Sulthan I thought about that as an option but since the code that creates the additional window is in an entirely different class I would have to use a singleton. I thought there could possible be an easier way if I could use the window's on and off properties (which I cannot find)
– Lance Samaria
Jun 29 at 16:41
If the window is minimized then you should probably also make it not to be the key window. You are the one controlling which window is the key window. Also, you can just iterate over
UIApplication.shared.windows
, check the class of the window and whether it is minimized or not. You are already using singletons.– Sulthan
Jun 29 at 18:21
UIApplication.shared.windows
the minimized window when maximized takes over the entire view including the tabBar, basically it sits in front of everything, that's why I made it another uiwindow.
– Lance Samaria
Jun 29 at 18:45
But there is no reason why the window should stay "key" once it is minimized. You should make the other window to be the key window then.
– Sulthan
Jun 29 at 19:10
2 Answers
2
The summarize the advice in comments.
The problem is that the action sheet is always shown from the key window but the additional window remains key window even when minimized.
The obvious solution is to make the main window the key window when the additional one is being minimized. See UIWindow.makeKey() or UIWindow.makeKeyAndVisible().
Since UIApplication.shared.windows
are ordered by window level (the back one first), you can always reach the main window using UIApplication.shared.windows.first
.
UIApplication.shared.windows
UIApplication.shared.windows.first
Therefore
UIApplication.shared.windows.first?.makeKey()
will make the main window the key window and the minimized window will stop being the key window.
quick question, how do i call .resignKey() so I can toggle the key on and off when maximized and minimized. Apple says don't call it directly
– Lance Samaria
Jun 29 at 20:00
@LanceSamaria
resignKey
is not something you can call. It's a method you override in UIWindow
subclass to know when the window has finished being key
window. The only way how to make a window the key window is to call any of the methods above. For example you could UIApplication.shared.windows.first?.makeKey()
. Note that UIApplication.shared.windows
is ordered by the window level.– Sulthan
Jun 29 at 20:04
resignKey
UIWindow
key
UIApplication.shared.windows.first?.makeKey()
UIApplication.shared.windows
See your idea 100% worked but the new problem I ran into was since the additional window is no longer a key window, when it’s full screen the custom action sheet launches on the window behind it (the main window). I need to toggle between the 2 states. eg. if maximized { window.first?.makeKey } else { window.resignKey() }. I know I can’t call resignKey() directly but I need something to call to tell it to remove itself as the key window.
– Lance Samaria
Jun 29 at 20:14
@LanceSamaria As I said
UIApplication.shared.windows.first?.makeKey()
should do the trick. You just have to tell the other window to become "key".– Sulthan
Jun 29 at 20:19
UIApplication.shared.windows.first?.makeKey()
ohhhhh ok ill try it now, thanks
– Lance Samaria
Jun 29 at 20:19
Here's the code breakdown to @Sulthan 's accepted answer. Read the comments in the code for an explanation.
let myVC = MyController()
var nav: UINavigationController?
var window: UIWindow!
var maximized = true
override init() {
super.init()
window = UIWindow()
window.backgroundColor = .clear
window.windowLevel = UIWindowLevelStatusBar
nav = UINavigationController(rootViewController: myVC)
window.rootViewController = nav
window?.isHidden = false
// window?.makeKeyAndVisible() // don't call this because it doesn't need to be the keyWindow as of yet. The window?.isHidden property above this makes the window visible
}
func maximizeOrMinimizeWindow() {
if maximized {
window.first?.makeKey // when the additional window is maximized make it the keyWindow
} else {
UIApplication.shared.windows.first?.makeKey() // when the additional window is minimized set the main window back as the key window
}
}
It should also be stated then when the additional window is removed from the superview or destroyed make sure to set the main window back as the keyWindow using UIApplication.shared.windows.first?.makeKey()
UIApplication.shared.windows.first?.makeKey()
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Well, you are using the key window. Why dont you just store references to the windows instead? Or dont make the secondary window a key window?
– Sulthan
Jun 29 at 16:37