[IOS] To allow rotation of only a specific screen

Overview

It's easy to not rotate on all screens, allow rotation on all screens, and not rotate only specific screens, but ** allow rotation on specific screens ** is quite annoying. This article will list several methods, so I think you should take the best method at any given time.

1. If you do it honestly

This is the most orthodox method. In the General settings

  1. Portrait
  2. Landscape Left
  3. Landscape Right
  4. Upside Down, if necessary

Check the box to allow rotation in the overall settings. After that, in all view controllers except the screen you want to rotate, allow only the vertical screen as follows.

override var supportedInterfaceOrientations: UIInterfaceOrientationMask { .portrait }

With the above steps, you can make only certain screens rotatable, but some challenges remain. First, it has a wide range of influence. If you are in the early stages of development, you may not care, but if you do this with a large existing application that already has dozens of screens, it is difficult because you have to check the behavior other than the screen you want to rotate. Also, when creating a new screen in the future, we must remember to allow only the vertical screen. If you have a common class like BaseViewController, you can specify it there and the changes will be small.

2. When you want to complete the process only on the target screen

If you decline first, this method touches private properties and may not be available depending on the iOS version or may be rejected by the review. Method 1 will affect all screens that you do not want to rotate, but this method is completed only for the screen that you want to rotate.

First, implement the following within AppDelegate.

    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        if let rootViewController = UIApplication.getTopViewController() {
            //Only HogeViewController allows rotation
            if rootViewController is HogeViewController {
                return .allButUpsideDown
            }
        }
        //Other than that, only the vertical screen
        return .portrait
    }

Create a method to get the frontmost view controller used in the above code.

extension UIApplication {

    ///Get the view controller displayed at the top
    static func getTopViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        
        if let nav = base as? UINavigationController {
            return getTopViewController(base: nav.visibleViewController)
            
        } else if let tab = base as? UITabBarController, let selected = tab.selectedViewController {
            return getTopViewController(base: selected)
            
        } else if let presented = base?.presentedViewController {
            return getTopViewController(base: presented)
        }
        
        return base
    }
}

By implementing the above, it is possible to allow rotation only on the target screen. However, with these alone, when transitioning to another screen during rotation, the other screen will also be displayed in a rotated state. Therefore, it is necessary to forcibly return the rotation of the screen at the time of transition as follows.

class HogeViewController {
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    
        if self.isMovingFromParentViewController {
            UIDevice.current.setValue(Int(UIInterfaceOrientation.portrait.rawValue), forKey: "orientation")
        }
    }
}

ʻUIDevice.current.setValue (rotation direction, forKey: "orientation") `is a well-known technique for forcibly rotating, but it is not a legitimate method because it accesses private properties.

3. Return the rotation on the transition destination screen

In method 2, the range of influence is smaller, but the process of returning the rotation is somewhat black magic. Therefore, the process of returning the rotation is performed on the transition destination screen. For example

FirstViewController -> HogeViewController -> FugaViewController

If such a transition can occur, you can explicitly specify the rotation direction with FirstVC and FugaVC.

class FirstViewController {
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask { .portrait }
}

class FugaViewController {
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask { .portrait }
}

However, when using this method, when a new wire is created from HogeVC and when a new wire is created to HogeVC, it is necessary to fix the rotation direction in the same way. Compared to method 1, the range of influence has decreased, but after all, it seems that future implementations need to be careful.

What other methods are there

In mono's slide, it seems that it is implemented by the method using aspect orientation, and there seems to be various methods. After all, it is difficult to add rotation control later, so I think it is best to consider this area from the beginning if possible.

end

Recommended Posts

[IOS] To allow rotation of only a specific screen
Set the time of LocalDateTime to a specific time
I want to make a specific model of ActiveRecord ReadOnly
[ruby] Creating a program that responds only to specific conditions
[Rails] Allow only people with specific server residents/specific roles of Discord to authenticate in sign-in
How to make a splash screen
When you want Rails to disable a session for a specific controller only
[Java] How to get to the front of a specific string using the String class
[Swift5] How to create a splash screen
Ability to display a list of products
Use Stream # collect to retrieve and list only specific fields from a JavaBean list
Add class only to specific elements with V-for
Scraping and writing specific elements to a file
iOS app development: Timer app (6. Creation of setting screen)
A summary of only Rails tutorial setup related
[Java] Add quotes only to specific CSV columns
A story addicted to EntityNotFoundException of getOne of JpaRepository
Make a margin to the left of the TextField