code

Swift에서만 한 뷰 컨트롤러의 방향을 세로 모드로 고정하는 방법

codestyles 2020. 10. 13. 07:49
반응형

Swift에서만 한 뷰 컨트롤러의 방향을 세로 모드로 고정하는 방법


내 앱이 모든 방향을 지원했기 때문에. 특정 UIViewController에 세로 모드 만 잠그고 싶습니다.

(예 : 탭이있는 응용 프로그램이고 로그인보기가 모달로 나타날 때 사용자가 장치를 회전하거나 현재 장치 방향이 어떻게 될지에 관계없이 로그인보기 만 세로 모드로 설정하고 싶습니다)


여러 탐색 컨트롤러 및 / 또는 탭보기 컨트롤러가있는 것과 같이 복잡한보기 계층 구조가있는 경우 상황이 매우 지저분해질 수 있습니다.

이 구현은 개별 뷰 컨트롤러에 배치하여 방향을 잠그고 싶을 때 설정합니다. 앱 델리게이트에 의존하여 하위 뷰를 반복하여 찾는 대신.

스위프트 3 & 4

AppDelegate에서 :

/// set orientations you want to be allowed in this property by default
var orientationLock = UIInterfaceOrientationMask.all

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return self.orientationLock
}

다른 전역 구조체 또는 도우미 클래스에서 AppUtility를 만들었습니다.

struct AppUtility {

    static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {

        if let delegate = UIApplication.shared.delegate as? AppDelegate {
            delegate.orientationLock = orientation
        }
    }

    /// OPTIONAL Added method to adjust lock and rotate to the desired orientation
    static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {

        self.lockOrientation(orientation)

        UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
        UINavigationController.attemptRotationToDeviceOrientation()
    }

}

그런 다음 원하는 ViewController에서 방향을 잠그고 싶습니다.

 override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    AppUtility.lockOrientation(.portrait)
    // Or to rotate and lock
    // AppUtility.lockOrientation(.portrait, andRotateTo: .portrait)

}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    // Don't forget to reset when view is being removed
    AppUtility.lockOrientation(.all)
}

iPad 또는 Universal App

대상 설정-> 일반-> 배포 정보에서 "전체 화면 필요"가 선택되어 있는지 확인합니다. supportedInterfaceOrientationsFor확인하지 않으면 delegate가 호출되지 않습니다.여기에 이미지 설명 입력


스위프트 4

여기에 이미지 설명 입력 AppDelegate

var orientationLock = UIInterfaceOrientationMask.all

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return self.orientationLock
}
struct AppUtility {
    static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
        if let delegate = UIApplication.shared.delegate as? AppDelegate {
            delegate.orientationLock = orientation
        }
    }

    static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
        self.lockOrientation(orientation)
        UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
    }
}

ViewController는 세로 방향 만 필요한 경우 다음 줄을 추가하십시오. ViewController가 세로 모드를 표시하기 위해 필요한 모든 것에 이것을 적용해야합니다.

override func viewWillAppear(_ animated: Bool) {
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.portrait, andRotateTo: UIInterfaceOrientation.portrait)
    }

그러면 장치의 물리적 방향에 따라 다른 Viewcontroller의 화면 방향이됩니다.

override func viewWillDisappear(_ animated: Bool) {
        AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.all)

    }

초상화를 강제로 잠 그려면 다음 코드를 추가하십시오.

override func viewDidLoad() {
    super.viewDidLoad()

    // Force the device in portrait mode when the view controller gets loaded
    UIDevice.currentDevice().setValue(UIInterfaceOrientation.Portrait.rawValue, forKey: "orientation") 
}

override func shouldAutorotate() -> Bool {
    // Lock autorotate
    return false
}

override func supportedInterfaceOrientations() -> Int {

    // Only allow Portrait
    return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {

    // Only allow Portrait
    return UIInterfaceOrientation.Portrait
}

AppDelegate에서-supportedInterfaceOrientationsForWindow를 전체 애플리케이션이 지원할 방향으로 설정합니다.

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.All
} 

이것은 귀하의 문제 및 기타 관련 문제에 대한 일반적인 솔루션입니다.

1. 보조 클래스 UIHelper를 만들고 다음 메서드를 적용합니다.

    /**This method returns top view controller in application  */
    class func topViewController() -> UIViewController?
    {
        let helper = UIHelper()
        return helper.topViewControllerWithRootViewController(rootViewController: UIApplication.shared.keyWindow?.rootViewController)
    }

    /**This is a recursive method to select the top View Controller in a app, either with TabBarController or not */
    private func topViewControllerWithRootViewController(rootViewController:UIViewController?) -> UIViewController?
    {
        if(rootViewController != nil)
        {
            // UITabBarController
            if let tabBarController = rootViewController as? UITabBarController,
                let selectedViewController = tabBarController.selectedViewController {
                return self.topViewControllerWithRootViewController(rootViewController: selectedViewController)
            }

            // UINavigationController
            if let navigationController = rootViewController as? UINavigationController ,let visibleViewController = navigationController.visibleViewController {
                return self.topViewControllerWithRootViewController(rootViewController: visibleViewController)
            }

            if ((rootViewController!.presentedViewController) != nil) {
                let presentedViewController = rootViewController!.presentedViewController;
                return self.topViewControllerWithRootViewController(rootViewController: presentedViewController!);
            }else
            {
                return rootViewController
            }
        }

        return nil
    }

2. 당신의 욕망 행동으로 프로토콜을 만듭니다. 당신의 특정한 경우는 초상화가 될 것입니다.

프로토콜 orientationIsOnlyPortrait {}

참고 : 원하는 경우 UIHelper 클래스 상단에 추가하세요.

3. 뷰 컨트롤러 확장

귀하의 경우 :

class Any_ViewController: UIViewController,orientationIsOnlyPortrait {

   ....

}

4. 앱 델리게이트 클래스에서 다음 메서드를 추가합니다.

 func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        let presentedViewController = UIHelper.topViewController()
        if presentedViewController is orientationIsOnlyPortrait {
            return .portrait
        }
        return .all
    }

최종 참고 사항 :

  • 더 많은 클래스가 세로 모드에 있으면 해당 프로토콜을 확장하십시오.
  • 뷰 컨트롤러에서 다른 동작을 원하면 다른 프로토콜을 만들고 동일한 구조를 따르십시오.
  • 이 예제는 푸시 뷰 컨트롤러 후 방향 변경 문제를 해결합니다.

스위프트 3 & 4

다음 supportedInterfaceOrientations과 같이 특정 UIViewController 속성을 설정합니다 .

class MyViewController: UIViewController {

    var orientations = UIInterfaceOrientationMask.portrait //or what orientation you want
    override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
    get { return self.orientations }
    set { self.orientations = newValue }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //...
}

최신 정보

당신이 때이 솔루션은 작동 viewController되고 있지 임베디드 UINavigationController, 부모의 ViewController에서 방향 상속 때문이다.
이 경우 하위 클래스를 만들고 UINavigationViewController여기에 이러한 속성을 설정할 수 있습니다.


이 스레드에는 많은 훌륭한 답변이 있지만 내 요구와 일치하는 것은 없습니다. 각 탭에 탐색 컨트롤러가있는 탭 앱이 있고 하나의보기는 회전해야하고 다른보기는 세로로 잠 가야했습니다. 내비게이션 컨트롤러가 어떤 이유로 하위 뷰의 크기를 적절하게 조정하지 않았습니다. 답변 과 결합하여 (Swift 3에서) 해결책을 찾았고 레이아웃 문제가 사라졌습니다. @bmjohns가 제안한대로 구조체를 만듭니다.

import UIKit

struct OrientationLock {

    static func lock(to orientation: UIInterfaceOrientationMask) {
        if let delegate = UIApplication.shared.delegate as? AppDelegate {
            delegate.orientationLock = orientation
        }
    }

    static func lock(to orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation: UIInterfaceOrientation) {
        self.lock(to: orientation)
        UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
    }
} 

그런 다음 UITabBarController 하위 클래스 :

    import UIKit

class TabBarController: UITabBarController, UITabBarControllerDelegate {
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.delegate = self
    }

    func tabBarControllerSupportedInterfaceOrientations(_ tabBarController: UITabBarController) -> UIInterfaceOrientationMask {
        if tabBarController.selectedViewController is MyViewControllerNotInANavigationControllerThatShouldRotate {
            return .allButUpsideDown
        } else if let navController = tabBarController.selectedViewController as? UINavigationController, navController.topViewController is MyViewControllerInANavControllerThatShouldRotate {
            return .allButUpsideDown
        } else {
            //Lock view that should not be able to rotate
            return .portrait
        }
    }

    func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
        if viewController is MyViewControllerNotInANavigationControllerThatShouldRotate {
            OrientationLock.lock(to: .allButUpsideDown)
        } else if let navController = viewController as? UINavigationController, navController.topViewController is MyViewControllerInANavigationControllerThatShouldRotate {
            OrientationLock.lock(to: .allButUpsideDown)
        } else {
            //Lock orientation and rotate to desired orientation
            OrientationLock.lock(to: .portrait, andRotateTo: .portrait)
        }
        return true
    }
}

스토리 보드에있는 TabBarController의 클래스를 새로 만든 하위 클래스로 변경하는 것을 잊지 마십시오.


가로 방향을 앱의 모든보기로 설정하고 하나의보기 만 모든 방향으로 허용하려면 (예 : 카메라 롤을 추가 할 수 있음) :

AppDelegate.swift에서 :

var adaptOrientation = false

에서 : didFinishLaunchingWithOptions

NSNotificationCenter.defaultCenter().addObserver(self, selector: "adaptOrientationAction:", name:"adaptOrientationAction", object: nil)

AppDelegate.swift의 다른 곳 :

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
    return checkOrientation(self.window?.rootViewController)
}

func checkOrientation(viewController:UIViewController?)-> Int{
    if (adaptOrientation == false){
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }else {
        return Int(UIInterfaceOrientationMask.All.rawValue)
    }
}

func adaptOrientationAction(notification: NSNotification){
    if adaptOrientation == false {
        adaptOrientation = true
    }else {
        adaptOrientation = false
    }
}

그런 다음 모든 방향을 가질 수 있도록 원하는 뷰로 이동합니다.

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
    if (segue.identifier == "YOURSEGUE") {
        NSNotificationCenter.defaultCenter().postNotificationName("adaptOrientationAction", object: nil)
    }
}

override func viewWillAppear(animated: Bool) {
    if adaptOrientation == true {
        NSNotificationCenter.defaultCenter().postNotificationName("adaptOrientationAction", object: nil)
    }
}

마지막으로 장치 방향을 선택합니다.-세로-가로 왼쪽-가로 오른쪽


다음으로 새 확장 만들기

import UIKit

extension UINavigationController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }
}

extension UITabBarController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }
}

다음은 Swift 4.2 (iOS 12.2)에서 저를 위해 작동하는 간단한 방법입니다 UIViewController. shouldAutorotate를 비활성화하려는 경우에 이것을 넣으십시오 .

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .portrait
}

.portrait부분은 어떤 방향으로 (들)을 유지하기에, 당신 등이 변경할 수를 알려줍니다. 선택은 : .portrait, .all, .allButUpsideDown, .landscape, .landscapeLeft, .landscapeRight, .portraitUpsideDown.


bmjohns-> 당신은 나의 구세주입니다. 이것이 유일하게 작동하는 솔루션입니다 (AppUtility 구조체 사용).

이 클래스를 만들었습니다.

class Helper{
    struct AppUtility {

        static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {

            if let delegate = UIApplication.shared.delegate as? AppDelegate {
                delegate.orientationLock = orientation
            }
        }

        /// OPTIONAL Added method to adjust lock and rotate to the desired orientation
        static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {

            self.lockOrientation(orientation)

            UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
        }

    }
}

지시 사항을 따르면 모든 것이 Swift 3-> xcode 버전 8.2.1에서 완벽하게 작동합니다.


iOS 10 및 11부터 iPad는 Slide Over 및 Split View를 지원합니다. Slide Over 및 Split View에서 앱을 활성화하려면 체크를 해제 Requires full screen 해야 합니다. , 앱이 Slide Over 및 Split View를 지원하려는 경우 허용 된 답변을 사용할 수 없습니다 . 여기 에서 Apple의 iPad 에서 멀티 태스킹 향상을 채택하는 방법에 대해 자세히 알아보십시오 .

나는 (1) 선택 취소 Requires full screen, (2) 하나의 기능 만 구현할 수있는 솔루션이 있습니다 ( appDelegate특히 대상 뷰 컨트롤러를 수정하고 싶지 않거나 수정할 수없는 경우), (3) 재귀 호출을 피할 수 있습니다. 도우미 클래스 나 확장이 필요하지 않습니다.

appDelegate.swift (Swift 4)

func application(_ application: UIApplication,
                 supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    // Search for the visible view controller
    var vc = window?.rootViewController
    // Dig through tab bar and navigation, regardless their order 
    while (vc is UITabBarController) || (vc is UINavigationController) {
        if let c = vc as? UINavigationController {
            vc = c.topViewController
        } else if let c = vc as? UITabBarController {
            vc = c.selectedViewController
        }
    }
    // Look for model view controller
    while (vc?.presentedViewController) != nil {
        vc = vc!.presentedViewController
    }
    print("vc = " + (vc != nil ? String(describing: type(of: vc!)) : "nil"))
    // Final check if it's our target class.  Also make sure it isn't exiting.
    // Otherwise, system will mistakenly rotate the presentingViewController.
    if (vc is TargetViewController) && !(vc!.isBeingDismissed) {
        return [.portrait]
    }
    return [.all]
}

편집하다

@bmjohns는이 함수가 iPad에서 호출되지 않는다고 지적했습니다. 나는 확인했고 그렇습니다. 그래서 좀 더 테스트를했고 몇 가지 사실을 알아 냈습니다.

  1. Requires full screeniPad에서 Slide Over 및 Slide View를 활성화하고 싶기 때문에 선택 취소했습니다 . 이를 위해서는 앱이 Info.plist :에서 iPad의 4 가지 방향을 모두 지원해야합니다 Supported interface orientations (iPad).

내 앱은 Facebook과 같은 방식으로 작동합니다. iPhone에서는 대부분 세로 모드로 고정되어 있습니다. 전체 화면으로 이미지를 볼 때 사용자가 더 나은보기를 위해 가로로 회전 할 수 있습니다. iPad에서 사용자는 모든 뷰 컨트롤러에서 원하는 방향으로 회전 할 수 있습니다. 따라서 iPad가 Smart Cover (왼쪽 가로)에 서있을 때 앱이 멋지게 보입니다.

  1. iPad application(_:supportedInterfaceOrientationsFor)가을 ( 를) 호출하려면 Info.plist에서 iPad의 경우 세로 만 유지하십시오. 앱이 Slide Over + Split View 기능을 잃게됩니다. 그러나 한 곳에서 모든 뷰 컨트롤러의 방향을 잠 그거나 잠금 해제 할 수 있으며 ViewController 클래스를 수정할 필요가 없습니다.

  2. 마지막으로이 함수는 뷰가 표시 / 제거 될 때 뷰 컨트롤러의 수명주기에서 호출됩니다. 앱이 다른 시간에 잠금 / 잠금 해제 / 방향 변경이 필요한 경우 작동하지 않을 수 있습니다.


이에 대한 실제 테스트 솔루션 . 내 예에서는 전체 앱이 세로 모드 여야하지만 한 화면의 방향 만 가로 모드 여야합니다.세로 모드 만 확인하여 앱의 세로 방향 만들기

위 답변에 설명 된대로 AppDelegate의 코드.

var orientationLock = UIInterfaceOrientationMask.all

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask 
{
  return self.orientationLock
}
struct AppUtility {  

static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
    if let delegate = UIApplication.shared.delegate as? AppDelegate {
        delegate.orientationLock = orientation
    }
}
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
self.lockOrientation(orientation)     
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}  
}

그런 다음 가로 방향 뷰 컨트롤러가 표시 / 푸시되기 전에이 코드를 기록하십시오.

override func viewWillAppear(_ animated: Bool) {  
super.viewWillAppear(animated)
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.portrait, andRotateTo: UIInterfaceOrientation.portrait)
}  

그런 다음 실제 viewcontroller에이 코드를 작성하십시오 (가로보기 용).

override func viewWillAppear(_ animated: Bool) {  
super.viewWillAppear(animated)
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.landscape, andRotateTo: UIInterfaceOrientation.landscape)
}  

위의 @bmjohn의 답변 덕분입니다. 다음은 다른 사람의 필사 시간을 절약하기 위해 해당 답변 코드의 Xamarin / C # 버전입니다.

AppDelegate.cs

 public UIInterfaceOrientationMask OrientationLock = UIInterfaceOrientationMask.All;
 public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, UIWindow forWindow)
 {
     return this.OrientationLock;
 }

Static OrientationUtility.cs 클래스 :

public static class OrientationUtility
{
    public static void LockOrientation(UIInterfaceOrientationMask orientation)
    {
        var appdelegate = (AppDelegate) UIApplication.SharedApplication.Delegate;
        if(appdelegate != null)
        {
            appdelegate.OrientationLock = orientation;
        }
    }

    public static void LockOrientation(UIInterfaceOrientationMask orientation, UIInterfaceOrientation RotateToOrientation)
    {
        LockOrientation(orientation);

        UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)RotateToOrientation), new NSString("orientation"));
    }
}

컨트롤러보기 :

    public override void ViewDidAppear(bool animated)
    {
       base.ViewWillAppear(animated);
       OrientationUtility.LockOrientation(UIInterfaceOrientationMask.Portrait, UIInterfaceOrientation.Portrait);
    }

    public override void ViewWillDisappear(bool animated)
    {
        base.ViewWillDisappear(animated);
        OrientationUtility.LockOrientation(UIInterfaceOrientationMask.All);
    }

참고 URL : https://stackoverflow.com/questions/28938660/how-to-lock-orientation-of-one-view-controller-to-portrait-mode-only-in-swift

반응형