Presenting a UIViewController from an embedded ViewController keeping its bounds - ios

I try to present a ViewController modally from a parent ViewController that's already embedded in a UIView. But whenever I try presenting it, it just pops over the entire window. I want it to be equally sized as its parent. I do not need an animation for the transition. The only thing that worked so far is to again add it's view manually and manipulate the constraints via auto layout. Therefore I would present the controller by hiding its corresponding view. But compared to present that seems more like a workaround than a solution. So far I tried some options on modalPresentationStyle, but none of them seem to work for me. Glad for any help.
Cheers!
class ViewController: UIViewController {
lazy var containerView: UIView = {
let view = UIView()
view.backgroundColor = .red
return view
}()
lazy var viewController: ParentViewController = {
let viewController = ParentViewController()
return viewController
}()
override func viewDidLoad() {
super.viewDidLoad()
containerView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(containerView)
containerView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
containerView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
containerView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.75).isActive = true
containerView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.75).isActive = true
viewController.view.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(viewController.view)
viewController.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
viewController.view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
viewController.view.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
viewController.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
viewController.didMove(toParent: self)
}
}
class ParentViewController: UIViewController {
#IBAction func buttonPressed(_ button: UIButton) {
let childController = UIViewController() // This View Controller should fit it´s parents size. Instead it´s just presented normally and fits the window
present(childController, animated: false)
}
}
Edit
Derived from the community answers I implemented following solution:
extension UIViewController {
func open(_ viewControllerToPresent: UIViewController, in view: UIView? = nil, animated: Bool, duration: TimeInterval = 0.25, completion: (() -> Void)? = nil) {
viewControllerToPresent.view.isHidden = true
open(viewControllerToPresent, in: view)
if animated {
viewControllerToPresent.view.alpha = 0.0
viewControllerToPresent.view.isHidden = false
UIView.animate(withDuration: duration) {
viewControllerToPresent.view.alpha = 1.0
} completion: { (_) in
completion?()
}
}
else {
viewControllerToPresent.view.isHidden = false
completion?()
}
}
func open(_ viewControllerToPresent: UIViewController, in view: UIView? = nil) {
let parentView = view ?? self.view!
addChild(viewControllerToPresent)
viewControllerToPresent.view.translatesAutoresizingMaskIntoConstraints = false
parentView.addSubview(viewControllerToPresent.view)
viewControllerToPresent.view.leadingAnchor.constraint(equalTo: parentView.leadingAnchor).isActive = true
viewControllerToPresent.view.trailingAnchor.constraint(equalTo: parentView.trailingAnchor).isActive = true
viewControllerToPresent.view.topAnchor.constraint(equalTo: parentView.topAnchor).isActive = true
viewControllerToPresent.view.bottomAnchor.constraint(equalTo: parentView.bottomAnchor).isActive = true
viewControllerToPresent.didMove(toParent: self)
}
func close(animated: Bool, duration: TimeInterval = 0.25, completion: (() -> Void)? = nil) {
if animated {
UIView.animate(withDuration: duration) {
self.view.alpha = 0.0
} completion: { (_) in
self.close()
completion?()
}
}
else {
close()
completion?()
}
}
func close() {
view.removeFromSuperview()
willMove(toParent: nil)
removeFromParent()
}
}

Related

How to change Status Bar Style inside ViewContoller if app based on SwiftUI

I'll try to change the status bar style inside the view controller because I want to use a different style depending on ViewController, and I try each of these recommendations How to change Status Bar text color in iOS, and I change option inside Info.plist , also not have an effect, what is wrong?
My code:
import SwiftUI
import UIKit
#main
struct TestAppearanceApp: App {
var body: some Scene {
WindowGroup {
WrapperUIVC_Hello().edgesIgnoringSafeArea(.all)
}
}
}
struct WrapperUIVC_Hello: UIViewControllerRepresentable {
func makeUIViewController(context: UIViewControllerRepresentableContext<WrapperUIVC_Hello>) -> some UIViewController {
let controller = ViewController()
controller.modalPresentationStyle = .automatic
return controller
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: UIViewControllerRepresentableContext<WrapperUIVC_Hello>) {
}
}
class ViewController: UIViewController {
lazy var button: UIButton = {
let view = UIButton()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .brown
view.addTarget(self, action: #selector(addInteraction(_:)), for: .touchUpInside)
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
view.addSubview(button)
button.heightAnchor.constraint(equalToConstant: 50).isActive = true
button.widthAnchor.constraint(equalToConstant: 100).isActive = true
button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
#objc func addInteraction(_ sender: UIButton) {
let vc = ViewControllerTest()
vc.modalPresentationStyle = .fullScreen
present(vc, animated: true)
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override func viewDidAppear(_ animated: Bool) {
setNeedsStatusBarAppearanceUpdate()
}
}
class ViewControllerTest: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .blue
setNeedsStatusBarAppearanceUpdate()
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
self.dismiss(animated: true)
}
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .darkContent
}
override func viewDidAppear(_ animated: Bool) {
setNeedsStatusBarAppearanceUpdate()
}
}

UIKit Change Presented View Controller's Layout Constraints Relative to Parent View

I'm working on a project in UIKit, without storyboards (only programmatic layout constraints) and, following this, I have a custom view controller like this:
#objc public class testController: UIViewController, QLPreviewControllerDataSource {
public override func viewDidAppear(_ animated: Bool) {
let previewController = QLPreviewController()
previewController.dataSource = self
self.view.translatesAutoresizingMaskIntoConstraints = false
previewController.view.widthAnchor.constraint(equalToConstant: 200).isActive = true
present(previewController, animated: true, completion: nil)
}
public func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return 1
}
public func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
guard let url = Bundle.main.url(forResource: String("beans"), withExtension: "pdf") else {
fatalError("Could not load \(index).pdf")
}
return url as QLPreviewItem
}
}
Then, in my main View Controller file, I add this testController as a subview like so:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let test = testController()
self.view.addSubview(test.view)
test.view.translatesAutoresizingMaskIntoConstraints = false
}
}
This works fine, but I'd like to be able to change my testController's programmatic layout constraints relative to it's parent view.
I've tried stuff like this in the main view controller (ViewController):
let test = testController()
self.view.addSubview(test.view)
test.view.translatesAutoresizingMaskIntoConstraints = false
test.view.widthAnchor.constraint(equalTo: 200, constant: 0).isActive = true
but this simply doesn't work/the view doesn't reflect these constraints at all and it seems like the only way I can successfully modify the constraints of the testController, is within the viewDidAppear function of the testController class.
However, if I try something like this:
public override func viewDidAppear(_ animated: Bool) {
let previewController = QLPreviewController()
previewController.dataSource = self
self.view.translatesAutoresizingMaskIntoConstraints = false
previewController.view.widthAnchor.constraint(equalToConstant: 200).isActive = true //notice how this works since it's a hardcoded 200
previewController.view.centerXAnchor.constraint(equalTo: self.view.centerXAnchor, constant: 0).isActive = true //this throws an error
present(previewController, animated: true, completion: nil)
}
I get an error thrown.
So I'd somehow like to access the parent of testViewController I guess, and use it for the constraints of the view. I've tried unsuccessfully using presentingViewController and parent for this, but they either return nil or throw an error.
Any help here would be appreciated.
This is sample to add view and change the constraints, in your example you have to add more constraint to test view.
class ViewController: UIViewController {
let buttonTest: UIButton = {
let button = UIButton()
button.setTitle("go to ", for: .normal)
button.backgroundColor = .green
button.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.view.addSubview(buttonTest)
buttonTest.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
buttonTest.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
buttonTest.centerXAnchor.constraint(equalTo: self.view.centerXAnchor)
])
}
#objc func buttonPressed() {
let secondView = SecondViewController()
self.view.addSubview(secondView.view)
secondView.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
secondView.view.topAnchor.constraint(equalTo: self.view.topAnchor,constant: 100),
secondView.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
secondView.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
secondView.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -100)
])
}
}
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .blue
}
}

How to preserve space occupied by status bar when hiding status bar animately?

I tend to hide the status bar, animated in the following way.
var statusBarHidden: Bool = false {
didSet {
UIView.animate(withDuration: Constants.config_shortAnimTime) { () -> Void in
self.setNeedsStatusBarAppearanceUpdate()
}
}
}
override var prefersStatusBarHidden: Bool {
return statusBarHidden
}
override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation{
return .slide
}
extension ViewController: SideMenuNavigationControllerDelegate {
func sideMenuWillAppear(menu: SideMenuNavigationController, animated: Bool) {
statusBarHidden = true
}
func sideMenuDidAppear(menu: SideMenuNavigationController, animated: Bool) {
}
func sideMenuWillDisappear(menu: SideMenuNavigationController, animated: Bool) {
}
func sideMenuDidDisappear(menu: SideMenuNavigationController, animated: Bool) {
statusBarHidden = false
}
}
However, I would also like to preserve the space occupied by status bar, so that when status bar appears, the entire app will not be "pushed up"
May I know how I can achieve so?
Thank you.
You can use additionalSafeAreaInsets to add a placeholder height, substituting the status bar.
But for devices with a notch like the iPhone 12, the space is automatically preserved, so you don't need to add any additional height.
class ViewController: UIViewController {
var statusBarHidden: Bool = false /// no more computed property, otherwise reading safe area would be too late
override var prefersStatusBarHidden: Bool {
return statusBarHidden
}
override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation{
return .slide
}
#IBAction func showButtonPressed(_ sender: Any) {
statusBarHidden.toggle()
if statusBarHidden {
sideMenuWillAppear()
} else {
sideMenuWillDisappear()
}
}
lazy var overlayViewController: UIViewController = {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
return storyboard.instantiateViewController(withIdentifier: "OverlayViewController")
}()
var additionalHeight: CGFloat {
if view.window?.safeAreaInsets.top ?? 0 > 20 { /// is iPhone X or other device with notch
return 0 /// add 0 height
} else {
/// the height of the status bar
return view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0.0
}
}
}
extension ViewController {
/// add placeholder height to substitute status bar
func addAdditionalHeight(_ add: Bool) {
if add {
if let navigationController = self.navigationController {
/// set insets of navigation controller if you're using navigation controller
navigationController.additionalSafeAreaInsets.top = additionalHeight
} else {
/// set insets of self if not using navigation controller
self.additionalSafeAreaInsets.top = additionalHeight
}
} else {
if let navigationController = self.navigationController {
/// set insets of navigation controller if you're using navigation controller
navigationController.additionalSafeAreaInsets.top = 0
} else {
/// set insets of self if not using navigation controller
self.additionalSafeAreaInsets.top = 0
}
}
}
func sideMenuWillAppear() {
addChild(overlayViewController)
view.addSubview(overlayViewController.view)
overlayViewController.view.frame = view.bounds
overlayViewController.view.frame.origin.x = -400
overlayViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
overlayViewController.didMove(toParent: self)
addAdditionalHeight(true) /// add placeholder height
UIView.animate(withDuration: 1) {
self.overlayViewController.view.frame.origin.x = -100
self.setNeedsStatusBarAppearanceUpdate() /// hide status bar
}
}
func sideMenuDidAppear() {}
func sideMenuWillDisappear() {
addAdditionalHeight(false) /// remove placeholder height
UIView.animate(withDuration: 1) {
self.overlayViewController.view.frame.origin.x = -400
self.setNeedsStatusBarAppearanceUpdate() /// show status bar
} completion: { _ in
self.overlayViewController.willMove(toParent: nil)
self.overlayViewController.view.removeFromSuperview()
self.overlayViewController.removeFromParent()
}
}
func sideMenuDidDisappear() {}
}
Result (Tested on iPhone 12, iPhone 8, iPad Pro 4th gen):
iPhone 12 (notch)
iPhone 8 (no notch)
iPhone 12 + navigation bar
iPhone 8 + navigation bar
Demo GitHub repo
First of all, it is not currently possible to make UINavigationController behave this way. However you can wrap your UINavigationController instance in a Container View Controller.
This will give you control over managing the top space from where the UINavigationController view layout starts. Inside this container class, you could manage it like following -
class ContainerViewController: UIViewController {
private lazy var statusBarBackgroundView: UIView = {
let view = UIView(frame: .zero)
view.backgroundColor = .clear
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var statusBarBackgroundViewHeightConstraint: NSLayoutConstraint = {
statusBarBackgroundView.heightAnchor.constraint(equalToConstant: 0)
}()
var statusBarHeight: CGFloat {
if #available(iOS 13.0, *) {
guard let statusBarMananger = self.view.window?.windowScene?.statusBarManager
else { return 0 }
return statusBarMananger.statusBarFrame.height
} else {
return UIApplication.shared.statusBarFrame.height
}
}
var statusBarHidden: Bool = false {
didSet {
self.statusBarBackgroundViewHeightConstraint.constant = self.statusBarHidden ? self.lastKnownStatusBarHeight : 0
self.view.layoutIfNeeded()
}
}
private var lastKnownStatusBarHeight: CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
let topView = self.statusBarBackgroundView
self.view.addSubview(topView)
NSLayoutConstraint.activate([
topView.topAnchor.constraint(equalTo: self.view.topAnchor),
topView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
statusBarBackgroundViewHeightConstraint,
topView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
])
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let height = self.statusBarHeight
if height > 0 {
self.lastKnownStatusBarHeight = height
}
}
func setUpNavigationController(_ navCtrl: UINavigationController) {
self.addChild(navCtrl)
navCtrl.didMove(toParent: self)
self.view.addSubview(navCtrl.view)
navCtrl.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
navCtrl.view.topAnchor.constraint(equalTo: statusBarBackgroundView.bottomAnchor),
navCtrl.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
navCtrl.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
navCtrl.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
])
self.view.layoutIfNeeded()
}
}
Now from your call site, you can do following -
class ViewController: UIViewController {
var statusBarHidden: Bool = false {
didSet {
UIView.animate(withDuration: Constants.config_shortAnimTime) { () -> Void in
/// Forward the call to ContainerViewController to act on this update
(self.navigationController?.parent as? ContainerViewController)?.statusBarHidden = self.statusBarHidden
/// Keep doing whatever you are doing now
self.setNeedsStatusBarAppearanceUpdate()
}
}
}
}

Hiding/showing status bar makes navigation bar jump down [duplicate]

I tend to hide the status bar, animated in the following way.
var statusBarHidden: Bool = false {
didSet {
UIView.animate(withDuration: Constants.config_shortAnimTime) { () -> Void in
self.setNeedsStatusBarAppearanceUpdate()
}
}
}
override var prefersStatusBarHidden: Bool {
return statusBarHidden
}
override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation{
return .slide
}
extension ViewController: SideMenuNavigationControllerDelegate {
func sideMenuWillAppear(menu: SideMenuNavigationController, animated: Bool) {
statusBarHidden = true
}
func sideMenuDidAppear(menu: SideMenuNavigationController, animated: Bool) {
}
func sideMenuWillDisappear(menu: SideMenuNavigationController, animated: Bool) {
}
func sideMenuDidDisappear(menu: SideMenuNavigationController, animated: Bool) {
statusBarHidden = false
}
}
However, I would also like to preserve the space occupied by status bar, so that when status bar appears, the entire app will not be "pushed up"
May I know how I can achieve so?
Thank you.
You can use additionalSafeAreaInsets to add a placeholder height, substituting the status bar.
But for devices with a notch like the iPhone 12, the space is automatically preserved, so you don't need to add any additional height.
class ViewController: UIViewController {
var statusBarHidden: Bool = false /// no more computed property, otherwise reading safe area would be too late
override var prefersStatusBarHidden: Bool {
return statusBarHidden
}
override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation{
return .slide
}
#IBAction func showButtonPressed(_ sender: Any) {
statusBarHidden.toggle()
if statusBarHidden {
sideMenuWillAppear()
} else {
sideMenuWillDisappear()
}
}
lazy var overlayViewController: UIViewController = {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
return storyboard.instantiateViewController(withIdentifier: "OverlayViewController")
}()
var additionalHeight: CGFloat {
if view.window?.safeAreaInsets.top ?? 0 > 20 { /// is iPhone X or other device with notch
return 0 /// add 0 height
} else {
/// the height of the status bar
return view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0.0
}
}
}
extension ViewController {
/// add placeholder height to substitute status bar
func addAdditionalHeight(_ add: Bool) {
if add {
if let navigationController = self.navigationController {
/// set insets of navigation controller if you're using navigation controller
navigationController.additionalSafeAreaInsets.top = additionalHeight
} else {
/// set insets of self if not using navigation controller
self.additionalSafeAreaInsets.top = additionalHeight
}
} else {
if let navigationController = self.navigationController {
/// set insets of navigation controller if you're using navigation controller
navigationController.additionalSafeAreaInsets.top = 0
} else {
/// set insets of self if not using navigation controller
self.additionalSafeAreaInsets.top = 0
}
}
}
func sideMenuWillAppear() {
addChild(overlayViewController)
view.addSubview(overlayViewController.view)
overlayViewController.view.frame = view.bounds
overlayViewController.view.frame.origin.x = -400
overlayViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
overlayViewController.didMove(toParent: self)
addAdditionalHeight(true) /// add placeholder height
UIView.animate(withDuration: 1) {
self.overlayViewController.view.frame.origin.x = -100
self.setNeedsStatusBarAppearanceUpdate() /// hide status bar
}
}
func sideMenuDidAppear() {}
func sideMenuWillDisappear() {
addAdditionalHeight(false) /// remove placeholder height
UIView.animate(withDuration: 1) {
self.overlayViewController.view.frame.origin.x = -400
self.setNeedsStatusBarAppearanceUpdate() /// show status bar
} completion: { _ in
self.overlayViewController.willMove(toParent: nil)
self.overlayViewController.view.removeFromSuperview()
self.overlayViewController.removeFromParent()
}
}
func sideMenuDidDisappear() {}
}
Result (Tested on iPhone 12, iPhone 8, iPad Pro 4th gen):
iPhone 12 (notch)
iPhone 8 (no notch)
iPhone 12 + navigation bar
iPhone 8 + navigation bar
Demo GitHub repo
First of all, it is not currently possible to make UINavigationController behave this way. However you can wrap your UINavigationController instance in a Container View Controller.
This will give you control over managing the top space from where the UINavigationController view layout starts. Inside this container class, you could manage it like following -
class ContainerViewController: UIViewController {
private lazy var statusBarBackgroundView: UIView = {
let view = UIView(frame: .zero)
view.backgroundColor = .clear
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var statusBarBackgroundViewHeightConstraint: NSLayoutConstraint = {
statusBarBackgroundView.heightAnchor.constraint(equalToConstant: 0)
}()
var statusBarHeight: CGFloat {
if #available(iOS 13.0, *) {
guard let statusBarMananger = self.view.window?.windowScene?.statusBarManager
else { return 0 }
return statusBarMananger.statusBarFrame.height
} else {
return UIApplication.shared.statusBarFrame.height
}
}
var statusBarHidden: Bool = false {
didSet {
self.statusBarBackgroundViewHeightConstraint.constant = self.statusBarHidden ? self.lastKnownStatusBarHeight : 0
self.view.layoutIfNeeded()
}
}
private var lastKnownStatusBarHeight: CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
let topView = self.statusBarBackgroundView
self.view.addSubview(topView)
NSLayoutConstraint.activate([
topView.topAnchor.constraint(equalTo: self.view.topAnchor),
topView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
statusBarBackgroundViewHeightConstraint,
topView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
])
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let height = self.statusBarHeight
if height > 0 {
self.lastKnownStatusBarHeight = height
}
}
func setUpNavigationController(_ navCtrl: UINavigationController) {
self.addChild(navCtrl)
navCtrl.didMove(toParent: self)
self.view.addSubview(navCtrl.view)
navCtrl.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
navCtrl.view.topAnchor.constraint(equalTo: statusBarBackgroundView.bottomAnchor),
navCtrl.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
navCtrl.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
navCtrl.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
])
self.view.layoutIfNeeded()
}
}
Now from your call site, you can do following -
class ViewController: UIViewController {
var statusBarHidden: Bool = false {
didSet {
UIView.animate(withDuration: Constants.config_shortAnimTime) { () -> Void in
/// Forward the call to ContainerViewController to act on this update
(self.navigationController?.parent as? ContainerViewController)?.statusBarHidden = self.statusBarHidden
/// Keep doing whatever you are doing now
self.setNeedsStatusBarAppearanceUpdate()
}
}
}
}

My GameScene Freezes when i dismiss modally presented viewController

I am working on SpriteKit Game. From within GameScene i want to represent another viewController. I have done it correctly, but when i dismiss Modally presented viewController, GameScene on my Root viewController freezes. Here is my code on GameScene....
NotificationCenter.default.post(name: NSNotification.Name(rawValue:"present"), object:nil)
Here is my code for root viewController(GameViewController)
override func viewDidLoad() {
super.viewDidLoad()
let gameScene = GameScene()
let skView = self.view as! SKView
skView.showsFPS = true
skView.ignoresSiblingOrder = true
let size = CGSize(width:590, height:390)
/* Set the scale mode to scale to fit the window */
//menuScene.scaleMode = .aspectFit
// menuScene.anchorPoint = CGPoint(x:0, y:0)
//skView.allowsTransparency = true
//size our scene to fit the view exactly:
// let rect1 = CGRect(origin:point, size:size)
//skView.setNeedsUpdateConstraints()
gameScene.size = CGSize(width:size.width, height:size.height)
gameScene.scaleMode = .aspectFill
skView.presentScene(gameScene)
skView.translatesAutoresizingMaskIntoConstraints = false
skView.ignoresSiblingOrder = true
skView.showsFPS = true
skView.showsNodeCount = true
NotificationCenter.default.addObserver(self, selector: #selector(self.presentVC), name: NSNotification.Name(rawValue:"present"), object: nil)
}
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override var prefersStatusBarHidden: Bool {
return true
}
func presentVC(){
let toViewController = viewController() as UIViewController
toViewController.modalPresentationStyle = .overFullScreen
self.present(toViewController, animated: true, completion: nil)
toViewController.transitioningDelegate = self
print("presenting next")
}
And Here is the code for another viewController that is to be represented modally over rootViewController:
override func viewDidLoad() {
super.viewDidLoad()
let imageView = UIImageView(image:UIImage(named:"Background1"))
imageView.frame = CGRect(x:0, y:0, width:1000, height:800)
let aButton = UIButton()
aButton.frame = CGRect(x:view.frame.width/2 - 50, y:view.frame.height/2 - 50, width:100, height:100)
aButton.setTitle("aButton", for: .normal)
aButton.backgroundColor = .green
aButton.addTarget(self, action: #selector(pressed), for: .touchUpInside)
aButton.isEnabled = true
view.addSubview(imageView)
view.addSubview(aButton)
}
func pressed(){
dismissVC()}
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override var prefersStatusBarHidden: Bool {
return true
}
func dismissVC(){
self.dismiss(animated: true, completion: nil)
print("returning previous")
}
Here is the answer with explanation. First of all it was not GameScene in frozen state. But it was view of another viewController that was present even after completion of activity on modally presented viewController. Presence of view of another viewController was due to nonExecution of viewController dismiss code inside that viewController. So presence of another viewController view was not allowing me to interact with my app. Now Solution is, In above Posted question, In GameViewController code i have added presentVC() function. Inside that instead of line:
self.present(toViewController, animated: true, completion: nil)
Use following line:
self.show(toViewController, sender:nil)

Resources