[ios] iOS 8에서 뷰 컨트롤러 방향을 강제하는 방법은 무엇입니까?

iOS 8 이전에는 supportedInterfaceOrientations shouldAutoRotate 대리자 메서드 하여 앱 방향을 특정 방향으로 강제했습니다. 아래 코드 스 니펫을 사용하여 응용 프로그램을 원하는 방향으로 프로그래밍 방식으로 회전했습니다. 먼저 상태 표시 줄 방향을 변경하고 있습니다. 그런 다음 모달 뷰를 제시하고 즉시 닫으면 뷰가 원하는 방향으로 회전합니다.

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:YES];
UIViewController *c = [[UIViewController alloc]init];
[self presentViewController:vc animated:NO completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];

그러나 이것은 iOS 8에서 실패합니다. 또한 사람들이 iOS 8부터는이 접근법을 항상 피해야한다고 제안한 스택 오버플로에 대한 답변을 보았습니다.

좀 더 구체적으로 말하면, 내 응용 프로그램은 범용 유형의 응용 프로그램입니다. 총 3 개의 컨트롤러가 있습니다.

  1. 퍼스트 뷰 컨트롤러 -iPad에서는 모든 방향을 지원하고 iPhone에서는 세로 (홈 버튼 아래로) 만 지원해야합니다.

  2. Second View 컨트롤러 -모든 조건에서 가로 만 지원해야합니다.

  3. Third View 컨트롤러 -모든 조건에서 가로 만 지원해야합니다.

페이지 탐색을 위해 탐색 컨트롤러를 사용하고 있습니다. 첫 번째 뷰 컨트롤러에서 버튼 클릭 동작으로 두 번째 뷰 컨트롤러를 스택에 밀어 넣습니다. 따라서 장치 방향에 관계없이 두 번째 뷰 컨트롤러가 도착하면 앱은 가로 방향으로 만 잠 가야합니다.

다음은 내 것입니다 shouldAutorotatesupportedInterfaceOrientations두 번째와 세 번째 뷰 컨트롤러의 방법.

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(BOOL)shouldAutorotate {
    return NO;
}

iOS 8의 경우 특정 방향으로 뷰 컨트롤러를 잠그는 더 좋은 방법이 있습니까? 도와주세요 !!



답변

iOS 7-10의 경우 :

목표 -C :

[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeLeft) forKey:@"orientation"];
[UINavigationController attemptRotationToDeviceOrientation];

스위프트 3 :

let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()

- viewDidAppear:제시된 뷰 컨트롤러 에서 호출하면됩니다 .


답변

방향 회전은 내부 UINavigationController또는 내부에 있으면 조금 더 복잡합니다.UITabBarController . 문제는 뷰 컨트롤러가 이러한 컨트롤러 중 하나에 내장 된 경우 내비게이션 또는 탭 막대 컨트롤러가 우선하고 자동 회전 및 지원되는 방향을 결정한다는 것입니다.

UINavigationController 및 UITabBarController에서 다음 두 가지 확장을 사용하여 이러한 컨트롤러 중 하나에 포함 된 뷰 컨트롤러가 결정을 내릴 수 있습니다.

View Controller에 전원을 공급하십시오!

스위프트 2.3

extension UINavigationController {
    public override func supportedInterfaceOrientations() -> Int {
        return visibleViewController.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        return visibleViewController.shouldAutorotate()
    }
}

extension UITabBarController {
    public override func supportedInterfaceOrientations() -> Int {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations()
        }
        return super.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate()
        }
        return super.shouldAutorotate()
    }
}

스위프트 3

extension UINavigationController {
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return visibleViewController?.supportedInterfaceOrientations ?? super.supportedInterfaceOrientations
    }

    open override var shouldAutorotate: Bool {
        return visibleViewController?.shouldAutorotate ?? super.shouldAutorotate
    }
}

extension UITabBarController {
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations
        }
        return super.supportedInterfaceOrientations
    }

    open override var shouldAutorotate: Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate
        }
        return super.shouldAutorotate
    }
}

이제 supportedInterfaceOrientations메서드를 재정의하거나 재정의 할 수 있습니다shouldAutoRotate 잠 그려는보기 컨트롤러에서 . 그렇지 않으면 앱의 plist에 지정된 기본 방향 동작을 상속하려는 다른보기 컨트롤러에서 재정의를 생략 할 수 있습니다

회전 비활성화

class ViewController: UIViewController {
    override func shouldAutorotate() -> Bool {
        return false
    }
}

특정 방향으로 고정

class ViewController: UIViewController {
    override func supportedInterfaceOrientations() -> Int {
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }
}

이론적으로 이것은 모든 복잡한보기 컨트롤러 계층 구조에서 작동하지만 UITabBarController에 문제가 있음을 알았습니다. 어떤 이유로 기본 방향 값을 사용하려고합니다. 일부 문제를 해결하는 방법에 대해 배우려면 다음 블로그 게시물을 참조하십시오.

잠금 화면 회전


답변

이것이 나를 위해 일한 것입니다.

https://developer.apple.com/library//ios/documentation/UIKit/Reference/UIViewController_Class/index.html#//apple_ref/occ/clm/UIViewController/attemptRotationToDeviceOrientation

viewDidAppear : 메소드에서 호출하십시오.

- (void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    [UIViewController attemptRotationToDeviceOrientation];
}


답변

제공된보기 컨트롤러 인 경우 무시할 수 있음을 발견했습니다. preferredInterfaceOrientationForPresentation

빠른:

override func supportedInterfaceOrientations() -> Int {
  return Int(UIInterfaceOrientationMask.Landscape.rawValue)
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
  return UIInterfaceOrientation.LandscapeLeft
}

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


답변

이 방법은 Swift 2 iOS 8.x 에서 작동합니다 .

추신 (이 방법은 모든 viewController에서 자동 회전 해야하는 방향 함수를 재정의 할 필요가 없으며 AppDelegate에서 단 하나의 방법)

프로젝트 일반 정보에서 “전체 화면 필요”를 확인하십시오.
여기에 이미지 설명을 입력하십시오

따라서 AppDelegate.swift에서 변수를 만드십시오.

var enableAllOrientation = false

따라서이 기능을 넣으십시오.

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
        if (enableAllOrientation == true){
            return UIInterfaceOrientationMask.All
        }
        return UIInterfaceOrientationMask.Portrait
}

따라서 프로젝트의 모든 클래스에서 viewWillAppear에서이 변수를 설정할 수 있습니다.

override func viewWillAppear(animated: Bool)
{
        super.viewWillAppear(animated)
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        appDelegate.enableAllOrientation = true
}

장치 유형에 따라 선택해야하는 경우 다음을 수행 할 수 있습니다.

override func viewWillAppear(animated: Bool)
    {
        super.viewWillAppear(animated)
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        switch UIDevice.currentDevice().userInterfaceIdiom {
        case .Phone:
        // It's an iPhone
           print(" - Only portrait mode to iPhone")
           appDelegate.enableAllOrientation = false
        case .Pad:
        // It's an iPad
           print(" - All orientation mode enabled on iPad")
           appDelegate.enableAllOrientation = true
        case .Unspecified:
        // Uh, oh! What could it be?
           appDelegate.enableAllOrientation = false
        }
    }


답변

우선, 이것은 일반적으로 나쁜 생각입니다. 앱 아키텍처에 문제가 있지만, sh..t happens그렇다면 다음과 같이 만들 수 있습니다.

final class OrientationController {

    static private (set) var allowedOrientation:UIInterfaceOrientationMask = [.all]

    // MARK: - Public

    class func lockOrientation(_ orientationIdiom: UIInterfaceOrientationMask) {
        OrientationController.allowedOrientation = [orientationIdiom]
    }

    class func forceLockOrientation(_ orientation: UIInterfaceOrientation) {
        var mask:UIInterfaceOrientationMask = []
        switch orientation {
            case .unknown:
                mask = [.all]
            case .portrait:
                mask = [.portrait]
            case .portraitUpsideDown:
                mask = [.portraitUpsideDown]
            case .landscapeLeft:
                mask = [.landscapeLeft]
            case .landscapeRight:
                mask = [.landscapeRight]
        }

        OrientationController.lockOrientation(mask)

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

보다 AppDelegate

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // do stuff
    OrientationController.lockOrientation(.portrait)
    return true
}

// MARK: - Orientation

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

방향을 변경할 때마다 다음과 같이하십시오.

OrientationController.forceLockOrientation(.landscapeRight)

참고 : 때때로 이러한 호출에서 장치가 업데이트되지 않을 수 있으므로 다음과 같이해야합니다.

OrientationController.forceLockOrientation(.portrait)
OrientationController.forceLockOrientation(.landscapeRight)

그게 다야


답변

이것은 iOS 6 이상에서 작동하지만 iOS 8에서만 테스트했습니다. 서브 클래스 UINavigationController및 다음 메소드를 재정의하십시오.

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return UIInterfaceOrientationLandscapeRight;
}

- (BOOL)shouldAutorotate {
    return NO;
}

또는 보이는 뷰 컨트롤러에 문의하십시오

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return self.visibleViewController.preferredInterfaceOrientationForPresentation;
}

- (BOOL)shouldAutorotate {
    return self.visibleViewController.shouldAutorotate;
}

거기에 메소드를 구현하십시오.