How to change viewController based on device orientation

时间:2015-10-30 21:30:57

标签: ios iphone swift uiviewcontroller screen-orientation

for the last few days I've been trying to figure out a way to do this:

Change to CollectionViewController if in landscape mode. Change to ViewController if in portrait mode.

Pretty much the way Music app behaves.

The way I did it was to implement viewWillTransitionToSize() in my main portraitViewController class:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {

    let storyBoard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
    let portraitViewController = storyBoard.instantiateViewControllerWithIdentifier("portraitViewController") as! ViewController
    let landscapeViewController = storyBoard.instantiateViewControllerWithIdentifier("landscapeViewController") as! beerCollectionViewController

    if (UIDevice.currentDevice().orientation.isLandscape) {
        // In landscape

        presentViewController(landscapeViewController, animated: true, completion: nil)

    } else {
        // In portrait

        self.navigationController?.presentViewController(portraitViewController, animated: true, completion: nil)
       //let navVC = UINavigationController(rootViewController: portraitViewController)
       //presentViewController(navVC, animated: true, completion: nil)

        //Dismiss collectionViewController after switching back to portrait
        self.dismissViewControllerAnimated(true, completion: nil)
    }

}

Main viewController(portraitViewController) contains a tableview and a searchController that has a searchBar on top.

In storyboard, portraitViewController is embedded in a navigation controller, collectionViewController(landscapeViewController) is on its own.

It runs, but I get the following 2 warnings:

Attempt to present UINavigationController on ViewController whose view is not in the window hierarchy!

Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior (UISearchController)

Can someone point out what's going wrong here? If there's any tutorial/examples that can be of help I would greatly appreciate it! Thank you so much for your help

EDIT: Here is the final code that works

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {

    let storyBoard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())

    // In landscape
    if UIDeviceOrientationIsLandscape(UIDevice.currentDevice().orientation) {
        let landscapeVC = storyBoard.instantiateViewControllerWithIdentifier("landscapeViewController") as! beerCollectionViewController
        if presentedViewController != nil {
            if !presentedViewController!.isBeingDismissed() {
                self.dismissViewControllerAnimated(false, completion:  {
                    self.presentViewController(landscapeVC, animated: true, completion: nil)
                })
            }
        } else {
            self.presentViewController(landscapeVC, animated: true, completion: nil)
        }

    }
    // In portrait
    else {
        let navC = storyBoard.instantiateViewControllerWithIdentifier("navID") as! UINavigationController
        let portraitVC = storyBoard.instantiateViewControllerWithIdentifier("portraitViewController") as! ViewController

        if presentedViewController != nil {
            if !presentedViewController!.isBeingDismissed() {
                self.dismissViewControllerAnimated(false, completion:  {
                    navC.pushViewController(portraitVC, animated: true)
                })
            }
        } else {
            navC.pushViewController(portraitVC, animated: true)
        }
    }

1 个答案:

答案 0 :(得分:0)

出现这些警告或错误的原因是,在解除和呈现视图控制器时出现延迟,并且您对呈现和解除的调用彼此重叠。

报告视图不在层次结构中的第一个错误意味着您尝试在原始视图控制器或导航控制器上显示一个不再可用的视图,因为另一个视图控制器已经过模态显示。

关于在解除分配时加载视图的第二个错误表示在尝试另一个模式演示时,视图控制器解雇还没有完全完成。

为了防止出现这些问题,需要在呈现新的视图控制器之前确保完成解雇。这可以通过在dismiss方法中使用完成处理程序处理状态并添加isBeingDismissed状态的检查来完成。

以下是一些完成该操作的代码:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

    let storyboard = UIStoryboard(name: "Main", bundle: nil)

    if UIDeviceOrientationIsLandscape(UIDevice.currentDevice().orientation) {
        let landscapeVC = storyboard.instantiateViewControllerWithIdentifier("landscapeViewController") as! beerCollectionViewController

        if presentedViewController != nil {
            if !presentedViewController!.isBeingDismissed() {
                dismissViewControllerAnimated(false, completion:  {
                    self.presentViewController(landscapeVC!, animated: true, completion: nil)
                })
            }
        } else {
            self.presentViewController(landscapeVC!, animated: true, completion: nil)
        }
    } else { // Portrait
        let portraitVC = storyboard.instantiateViewControllerWithIdentifier("portraitViewController") as! ViewController

        if presentedViewController != nil {
            if !presentedViewController!.isBeingDismissed() {
                dismissViewControllerAnimated(false, completion:  {
                    self.presentViewController(portraitVC!, animated: true, completion: nil)
                })
            }
        } else {
            self.presentViewController(portraitVC!, animated: true, completion: nil)
        }
    }
}