Programing

iOS 6 : 일부보기를 세로로 제한하고 다른보기는 회전하도록 허용하려면 어떻게합니까?

lottogame 2020. 8. 20. 19:26
반응형

iOS 6 : 일부보기를 세로로 제한하고 다른보기는 회전하도록 허용하려면 어떻게합니까?


UINavigationController드릴 다운 인터페이스를 표시하기 위해 를 사용하는 iPhone 앱이 있습니다. 먼저 하나의보기, 다른 하나는 최대 4 단계 깊이입니다. 처음 세보기는 세로 방향으로 제한하고 마지막보기 만 가로로 회전하도록 허용해야합니다. 네 번째보기에서 세 번째보기로 돌아가고 네 번째보기는 가로 방향으로 돌아 갔을 때 모든 것이 다시 세로로 회전하기를 원합니다.

iOS 5에서는 shouldAutorotateToInterfaceOrientation:허용 가능한 방향에 대해 YES를 반환하도록 각 뷰 컨트롤러에서 간단히 정의 했습니다. 뷰 컨트롤러 # 4에서 # 3으로 돌아올 때 장치가 가로 방향으로 유지 되더라도 세로로 돌아가는 것을 포함하여 모든 것이 위에서 설명한대로 작동했습니다.

iOS 6에서 모든 뷰 컨트롤러는 가로 방향으로 회전하여 의도하지 않은 컨트롤러를 깨뜨립니다. iOS 6 릴리스 노트에는

더 많은 책임이 앱과 앱 델리게이트로 이동하고 있습니다. 이제 iOS 컨테이너 (예 UINavigationController:)는 자동 회전 여부를 결정하기 위해 자녀에게 문의하지 않습니다. [...] 시스템은 장치가 회전 할 때마다 또는 뷰 컨트롤러가 전체 화면 모달 프레젠테이션 스타일로 표시 될 때마다 지원되는 인터페이스 방향에 대해 최상위 전체 화면 뷰 컨트롤러 (일반적으로 루트 뷰 컨트롤러)에 요청합니다. 또한이 뷰 컨트롤러가 shouldAutorotate메서드 에서 YES를 반환하는 경우에만 지원되는 방향이 검색됩니다 . [...] 시스템은 앱의 supportedInterfaceOrientationsForWindow:메서드에서 반환 된 값과 supportedInterfaceOrientations최상위 전체 화면 컨트롤러 메서드 에서 반환 된 값을 교차하여 방향이 지원되는지 여부를 결정합니다 .

나는 서브 클래스 그래서 UINavigationController내 준 MainNavigationController부울 속성을 landscapeOK하고있는 허용 방향을 반환하려면이 옵션을 사용 supportedInterfaceOrientations. 그런 다음 각 뷰 컨트롤러의 viewWillAppear:메서드에 다음 과 같은 줄이 있습니다.

    [(MainNavigationController*)[self navigationController] setLandscapeOK:YES];

MainNavigationController원하는 행동 을 알려 줍니다.

여기에 질문이 있습니다. 이제 세로 모드에서 네 번째보기로 이동하고 전화기를 뒤집 으면 가로로 회전합니다. 이제 뒤로 버튼을 눌러 세로로만 작동해야하는 세 번째보기로 돌아갑니다. 그러나 그것은 뒤로 회전하지 않습니다. 그렇게하려면 어떻게해야합니까?

나는 시도했다

    [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait]

viewWillAppear내 세 번째 뷰 컨트롤러 방법에 있지만 아무것도하지 않습니다. 이것이 호출하기에 잘못된 방법입니까, 아니면 호출하기에 잘못된 곳입니까, 아니면 완전히 다른 방식으로 전체를 구현해야합니까?


나는 같은 문제가 있었고 나에게 맞는 해결책을 찾았습니다. 작동하려면 UINavigationController에서 구현 하는 것만으로 충분 하지 않습니다- (NSUInteger)supportedInterfaceOrientations . 또한 컨트롤러 # 3에서이 메서드를 구현해야합니다. 컨트롤러 # 4를 터뜨린 후 처음으로 세로 전용이됩니다. 그래서 내 UINavigationController에 다음 코드가 있습니다.

- (BOOL)shouldAutorotate
{
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    if (self.isLandscapeOK) {
        // for iPhone, you could also return UIInterfaceOrientationMaskAllButUpsideDown
        return UIInterfaceOrientationMaskAll;
    }
    return UIInterfaceOrientationMaskPortrait;
}

뷰 컨트롤러 # 3에서 다음을 추가합니다.

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

뷰 컨트롤러 # 1, # 2 및 # 4에 아무것도 추가 할 필요가 없습니다. 이것은 나를 위해 작동하며 도움이되기를 바랍니다.


CustomNavigationController 추가

다음 메소드를 재정의하십시오.

-(BOOL)shouldAutorotate
{
    return [[self.viewControllers lastObject] shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations
{
    return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}

이제 plist에 모든 방향을 추가하십시오.

여기에 이미지 설명 입력

보기 컨트롤러에서 필요한 것만 추가하십시오.

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

이러한 메서드는 탐색 컨트롤러 메서드를 재정의합니다.


SO에 대한 수많은 유사한 질문에서 모든 답변을 살펴본 결과 어떤 답변도 저에게 효과가 없었지만 몇 가지 아이디어를 얻었습니다. 문제를 해결 한 방법은 다음과 같습니다.

먼저 프로젝트 대상의 지원되는 인터페이스 방향에 회전 뷰에 대해 원하는 모든 방향이 포함되어 있는지 확인하십시오.

여기에 이미지 설명 입력

다음으로 카테고리를 만듭니다 UINavigationController(애플이 하위 클래스를 만들지 말라고 말했기 때문에).

@implementation UINavigationController (iOS6AutorotationFix)

-(BOOL)shouldAutorotate {
    return [self.topViewController shouldAutorotate];
}

@end

해당 카테고리와 회전 할 수있는 뷰 컨트롤러 ( RotatingViewController)를 탐색 컨트롤러를 포함해야하는 최상위 뷰 컨트롤러로 가져옵니다 . 해당 뷰 컨트롤러에서 shouldAutorotate다음과 같이 구현하십시오 . 회전하려는 뷰 컨트롤러와 동일하지 않아야합니다.

-(BOOL)shouldAutorotate {

    BOOL shouldRotate = NO;

    if ([navigationController.topViewController isMemberOfClass:[RotatingViewController class]] ) {
        shouldRotate = [navigationController.topViewController shouldAutorotate];
    }

    return shouldRotate;
}

마지막으로,에 RotatingViewController, 실행 shouldAutorotate하고 supportedInterfaceOrientations다음과 같이 :

-(BOOL)shouldAutorotate {
    // Preparations to rotate view go here
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskAllButUpsideDown; // or however you want to rotate
}

이 작업을 수행해야하는 이유는 iOS 6이 상위 뷰 컨트롤러 대신 루트 뷰 컨트롤러에 회전 제어를 제공하기 때문입니다. 개별 뷰의 회전이 스택의 다른 뷰와 다르게 동작하도록하려면 루트 뷰 컨트롤러에서 특정 사례를 작성해야합니다.


@Brian의 답변에 대해 언급 할만한 평판이 충분하지 않으므로 여기에 메모를 추가하겠습니다.

Brian은 iOS6가 rootViewController에 회전 제어를 제공한다고 언급했습니다. 이것은 언급 한대로 UINavigationController 일 수있을뿐만 아니라 저를위한 UITabBarController 일 수도 있습니다. 내 구조는 다음과 같습니다.

  • UITabBarController
    • UINavigationController
      • UIViewControllers ...
    • UINavigationController
      • UIViewControllers ...

그래서 먼저 사용자 지정 UITabBarController에 메서드를 추가 한 다음 사용자 지정 UINavigationController에, 마지막으로 특정 UIViewController에 메서드를 추가했습니다.

UITabBarController 및 UINavigationController의 예 :

- (BOOL)shouldAutorotate {
    return [self.viewControllers.lastObject shouldAutorotate];
}

- (NSUInteger)supportedInterfaceOrientations {
    return [self.viewControllers.lastObject supportedInterfaceOrientations];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return [self.viewControllers.lastObject shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return [self.viewControllers.lastObject preferredInterfaceOrientationForPresentation];
}

내 질문에 부분적으로 대답하고 싶습니다. viewWillAppear세 번째 방법 에서 사용되는 다음 코드 줄이 작동하는 것을 발견 UIViewController했습니다.

[[UIDevice currentDevice] 
      performSelector:NSSelectorFromString(@"setOrientation:") 
           withObject:(id)UIInterfaceOrientationPortrait];

하지만 저는이 솔루션이 마음에 들지 않습니다. Apple 문서 에 따라 장치 물리적 방향을 나타내는 읽기 전용 속성에 할당하는 트릭을 사용하고 있습니다. 사용자의 손에서 올바른 방향으로 이동하도록 iPhone에 지시하는 것과 같습니다.

나는 단순히 작동하기 때문에 이것을 내 앱에 남겨두고 싶습니다. 그러나 그것은 옳지 않다고 생각하기 때문에 깨끗한 해결책을 위해 질문을 열어두고 싶습니다.


이것은 iOS 6.0에서 방향 지원을 위해 사용하고 있습니다.

-(BOOL)shouldAutorotate{
    return YES;
}  

 - (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskAll;
}


- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{  
  return UIInterfaceOrientationPortrait;
}

이것은 높은 평가 스레드이기 때문에. 가장 쉬운 답이라고 생각하는 것을 추가하겠다고 생각했습니다. 이것은 ios8 이상에서 작동합니다.

-(BOOL)shouldAutorotate
{
    return YES;
}

-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}

그게 다야. 즐겨!

아, 그리고 내 ViewController는 탐색 컨트롤러에 포함되어 있으므로 어떤 식 으로든 하위 클래스를 지정하거나 구성 할 필요가 없습니다.


이것은 모든 사람에게 작동하지 않을 수도 있지만 나에게는 잘 작동합니다. 구현하는 대신 ...

[(MainNavigationController*)[self navigationController] setLandscapeOK:YES];

모든 컨트롤러의 viewWillAppear에서 UINavigationControllerDelegate 메서드 를 재정 의하여 UINavigationController 하위 클래스 내에서이 프로세스를 중앙 집중화하기로 결정했습니다.navigationController:willShowViewController:animated:

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {

    self.previousVCLandscapeOK = self.isLandscapeOK; // Store the current VC's orientation preference before pushing on the new VC so we can set this again from within the custom "back" method
    self.isLandscapeOK = NO; // Set NO as default for all VC's
    if ([viewController isKindOfClass:[YourViewController class]]) {
        self.isLandscapeOK = YES;
    }
}

nav 스택에서 VC를 꺼낼 때이 대리자 메서드가 호출되지 않는다는 것을 발견했습니다. UINavigationController 하위 클래스 내에서 뒤로 기능을 처리하고 있으므로 특정 VC에 대해 적절한 탐색 모음 단추와 작업을 설정할 수 있기 때문에 이것은 문제가되지 않았습니다.

if ([viewController isKindOfClass:[ShareViewController class]]) {

    UIButton* backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 57, 30)];
    [backButton setImage:[UIImage imageNamed:@"back-arrow"] forState:UIControlStateNormal];
    [backButton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
    UIBarButtonItem* backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
    viewController.navigationItem.leftBarButtonItem = backButtonItem;

    UIImageView* shareTitle = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"share-title"]];
    [shareTitle setContentMode:UIViewContentModeScaleAspectFit];
    [shareTitle setFrame:CGRectMake(0, 0, shareTitle.frame.size.width - 10, shareTitle.frame.size.height - 10)];
    viewController.navigationItem.titleView = shareTitle;

} else if(...) {
    ...
}

다음은 back스택에서 VC를 꺼내고 적절한 회전 기본 설정을 설정하는 방법입니다.

- (void)back {
    self.isLandscapeOK = self.previousVCLandscapeOK;
    self.previousVCLandscapeOK = NO;
    [self popViewControllerAnimated:YES];
}

보시다시피, 기본적으로 일어나는 일은 제가 먼저 두 가지 속성을 설정하는 것입니다.

@property (nonatomic) BOOL isLandscapeOK;
@property (nonatomic) BOOL previousVCLandscapeOK;

navigationController:willShowViewController:animated:있는 지원 방향이 제시 될 예정임을 VC 내에 결정됩니다. VC를 팝할 때 내 사용자 정의 "back"메서드가 호출되고 나는 isLandscapeOK를 previousVCLandscapeOK 값을 통해 저장된 값으로 설정합니다.

내가 말했듯이 이것은 모든 사람에게 작동하지 않을 수도 있지만 나에게는 잘 작동하며 각 뷰 컨트롤러에 코드를 추가하는 것에 대해 걱정할 필요가 없으며 모든 것을 UINavigationController 하위 클래스에 중앙 집중화 할 수있었습니다.

이것이 나처럼 누군가에게 도움이되기를 바랍니다. 고마워, Jeremy.


Info.plist 파일로 이동하여 변경하십시오.여기에 이미지 설명 입력


iOS 6 앱 세로 모드 만 강제하려는 경우 메서드 아래의 UIViewController 하위 클래스에 추가 할 수 있습니다.

- (BOOL)shouldAutorotate {
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        return YES;
    } else {
        return NO;
    }
}


- (NSUInteger)supportedInterfaceOrientations {
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        return UIInterfaceOrientationMaskAll;
    } else {
        return UIInterfaceOrientationMaskPortrait;
    }
}

나는 하나를 제외하고 모든 VC를 세로 방향으로 고정하고 싶었습니다. 이것이 나를 위해 일한 것입니다.

  1. Add support for all orientations in the plist file.
  2. In the root view controller, detect the kind of view controller thats on top of the window and set the orientation of the app accordingly in the supportedInterfaceOrientations method. For example, I needed my app to rotate only when the webview was on top of the stack. Here's what I added in my rootVC :

    -(NSUInteger)supportedInterfaceOrientations
    {
        UIViewController *topMostViewController = [[Utils getAppDelegate] appNavigationController].topViewController;
        if ([topMostViewController isKindOfClass:[SVWebViewController class]]) {
            return UIInterfaceOrientationMaskAllButUpsideDown;
        }
        return UIInterfaceOrientationMaskPortrait;
    }
    

I don't have enough reputation to answer @Ram S question under @micmdk reply so I'll add my note here.

When you use UITabbarController, try to change self.viewControllers.lastObject in @micmdk's code to self.selectedViewController like this:

- (BOOL)shouldAutorotate {
    return [self.selectedViewController shouldAutorotate];
}

- (NSUInteger)supportedInterfaceOrientations {
    return [self.selectedViewController supportedInterfaceOrientations];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return [self.selectedViewController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return [self.selectedViewController preferredInterfaceOrientationForPresentation];
}

You can implement and override shouldAutorotate() and supportedInterfaceOrientations var in all of your View Controller classes that should be presented in a different orientations than ones defined in PLIST of your app.

However, in a nontrivial User Interface you might face a problem to add it in dozens of classes and you do not want to make all of them subclass of several common that supports it (MyBaseTableViewController, MyBaseNavigationController and MyBaseTabBarController).

Since you cannot override those method/var on UIViewController directly, you may do that on its subclasses that are typically base classes of yours like UITableViewController, UINavigationController and UITabBarController.

따라서 몇 가지 확장을 구현하고도이 Swift 4 코드 스 니펫과 같은 다른 모든 방향과 다른 방향으로 표시되도록 MyPreciousViewController를 설정할 수 있습니다.

extension UITableViewController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {

    if let last = self.navigationController?.childViewControllers.last,
        last != self {
            return last.supportedInterfaceOrientations
    } else {
        return [.portrait]
    }
    }
}

extension MyPreciousViewController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {

    return [.portrait,.landscape]
    }
}


extension UINavigationController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {

        return [.portrait]
    }
}


extension UITabBarController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {

        return [.portrait]
    }
}

나는 같은 종류의 문제를 해결했습니다.

를 사용하여 UINavigationController뷰 컨트롤러를 푸시하는 경우 아래 방법을 설정해야합니다.

extension UINavigationController{

    override open var shouldAutorotate: Bool {

        if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))!
        {
            return true
        }
        return false
    }

    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {

        if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))!
        {
            return .portrait
        }
        return .landscapeRight

    }
    override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {

        if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))!
        {
            return .portrait
        }
        return .landscapeRight
    }
}

당신이 보여주고 싶은 LoginViewController사용 장소 UIViewController. 내 경우에는, 내가 보여주고 싶은 LoginViewControllerPortrait모드는 다른 ViewControllerslandscape모드.


이 문제를 해결하려면 다음 방법을 사용하십시오.

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

원하는 방향 만 돌려주세요 !!!

참고 URL : https://stackoverflow.com/questions/12630359/ios-6-how-do-i-restrict-some-views-to-portrait-and-allow-others-to-rotate

반응형