Programing

shouldAutorotateToInterfaceOrientation이 iOS 6에서 호출되지 않음

lottogame 2020. 11. 29. 09:30
반응형

shouldAutorotateToInterfaceOrientation이 iOS 6에서 호출되지 않음


MGSplitViewController를 사용 shouldAutorotateToInterfaceOrientation하고 있으며 회전시 마스터 뷰 컨트롤러의 크기를 제어하는 ​​데 사용 하고 있습니다.

iOS 5에서는 모두 잘 작동하지만 iOS 6 (시뮬레이터와 iPad 모두) shouldAutorotateToInterfaceOrientation에서는 호출되지 않습니다.

iOS 6의 최종 릴리스에서 수정 될 것으로 예상되는 버그입니까, 아니면 제가 알지 못하는 것이 변경 되었습니까?


이 글을주의 깊게 읽으시거나, 방문객의 모빌을 잡은 동물원의 침팬지처럼 테스트 장치를 돌리고, 미치고, 싸우고, 흔들면서 인생의 1-2 일을 잃을 수 있습니다! 조만간 ... 약속 :)

iOS 6에서

shouldAutorotateToInterfaceOrientation:

더 이상 사용되지 않으며 다음으로 대체됩니다.

shouldAutorotate

이는 iOS 6이 절대 호출하지 않음을 의미합니다 shouldAutorotateToInterfaceOrientation.

따라서 응용 프로그램에서 다음을 사용한 경우

BEFORE iOS6의 (iOS5를, iOS4 등)

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortrait) {
// your code for portrait mode

}

return YES;
}

당신은 사용해야합니다

iOS 6 이상 이후

- (BOOL)shouldAutorotate {

UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];

if (orientation == UIInterfaceOrientationPortrait) {
// your code for portrait mode

}

return YES;
}

조심하세요

UIInterfaceOrientation의 속성이며 UIApplication상태 표시 줄의 방향에 해당하는 4 가지 가능성 만 포함합니다.

UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,

UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,

UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,

UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft

그것을 혼동하지 마십시오

UIDeviceOrientation이는 UIDevice클래스 의 속성이며 7 개의 가능한 값을 포함합니다.

UIDeviceOrientationUnknown - Can not be determined

UIDeviceOrientationPortrait - Home button facing down

UIDeviceOrientationPortraitUpsideDown - Home button facing up

UIDeviceOrientationLandscapeLeft - Home button facing right

UIDeviceOrientationLandscapeRight - Home button facing left

UIDeviceOrientationFaceUp - Device is flat, with screen facing up

UIDeviceOrientationFaceDown - Device is flat, with screen facing down

이론적으로 UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];어떤 반환을 사용할 수도 있습니다 UIDeviceOrientation-장치의 실제 방향-하지만 UIDeviceOrientation항상 같지는 않다는 것을 알아야합니다 UIInterfaceOrientation!!! 예를 들어 장치가 일반 테이블에 있으면 예기치 않은 값을받을 수 있습니다.

인터페이스의 현재 방향 UIInterfaceOrientation orientation = self.interfaceOrientation;을 반환 하는 것도 사용할 수 UIInterfaceOrientation있지만의 속성 UIViewController이므로 UIViewController클래스 에서만이 항목에 액세스 할 수 있습니다 .

분명이 될 수 - - 당신이 모두 이전 iOS6의 (iOS3 / 4 / 5) iOS6의 장치를 지원하려는 경우 단지를 모두 사용 shouldAutorotateToInterfaceOrientation:하고 shouldAutorotate코드입니다.

iOS 6 에는 앱 시작 중에 기기가 확인하는 3 단계와 3 단계가 있으며, 원하는 경우 제어해야합니다.

1. Info.plist - Supported Interface Orientations

요약 탭에서 그래픽으로 설정할 수 있습니다. 허용되는 방향의 순서는 중요합니다.를 편집하여 수동으로 변경할 수 있으며 info.plist, 앱이 시작될 때 장치가 첫 번째 방향을 선택합니다! [UIDevice currentDevice].orientation특히 평평한 표면에서 앱을 테스트 할 때 알 수없는 가능성이있을 때 항상 앱이 시작되는 문제이므로 이는 매우 중요합니다 .

XCode의 plist 설정 (정보)

주의하십시오 (iPad) 또는 (iPhone) 확장으로 두 가지 다른 설정 가능성이 있으며, 그중 하나를 사용하면 현재 장치 또는 시뮬레이터의 해당 설정을 사용하고 확장이없는 일반 설정은 무시합니다. 따라서 iPhone 전용 앱을 실행하고 실수로 데이터없이 plist 어딘가에 "Supported Interface Orientations (iPad)"줄을 남겼다면 이전에 일반 설정에서 설정 한 규칙을 무시하게됩니다 (iPhone의 경우 ) 앱이 iPhone에서 지정된 방향을 사용하지 않고 iPad에서 사용하려는 경우에도 "귀하의 앱이 iPad에서 실행하기위한 요구 사항을 충족하지 않음을 발견했습니다."라는 텍스트와 함께 앱이 거부 될 수 있습니다. 예상치 못한 오류를 유발할 수 있습니다.

2. AppDelegate - application:supportedInterfaceOrientationsForWindow

허용하려는 모든 방향의 비트 마스크 목록을 반환하여 info.plist 설정을 재정의합니다.이 작업은 장치가 회전 할 때마다 적어도 한 번 호출됩니다.

3. Top-level view controller or RootViewController - supportedInterfaceOrientations

이는 앱 및 앱 델리게이트 집합과 교차를 제공하며 충돌을 방지하기 위해 0이 아닌 결과를 가져야합니다. 컨트롤러에 다른 메서드가 설치된 경우를 제외하고는 장치가 회전 할 때마다 적어도 한 번 호출됩니다.

shouldAutorotate

이는 앱의 허용 된 방향을 방해하고 BOOLwith default YES.

BE CAREFUL when you use `NavigationController`

당신의 맨 위의 컨트롤러와 AppDelegate같은 :

DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
UINavigationController *navigationController=[[UINavigationController alloc] initWithRootViewController:detailViewController];
self.window.rootViewController =nil;
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;

이 경우 최상위 컨트롤러이므로 클래스에 AppDelegate대한 범주 첨부로 다음 코드를 배치 NavigationController해야하며 하위 범주를 만들지 않은 경우 방향을 설정할 수있는 위치 / 코드가 없습니다. 설정이므로이 rootViewController경우 detailViewController방향에 대한 실제를 확인하도록 강제해야 합니다.

@implementation UINavigationController (OrientationSettings_IOS6)

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

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

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

@end

그런 다음 아래에서와 같이 iOS 6에서 사용할 수있는 모든 방법을 사용 하여 "최상위" ViewController(내 예에서는 detailViewController) 에서 선호하는 방향을 설정할 수 ViewControllers있습니다.

1. (BOOL)shouldAutorotate

2. (NSUInteger)supportedInterfaceOrientations

3. (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation

좋아, iOS6 iPad Simulator에서 작동하도록했습니다. 예. 내가 한 일은 다음과 같습니다.

전과 후에 보여 드리지만, 자명해야합니다.

전에

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

if (interfaceOrientation==UIInterfaceOrientationPortrait) {
 // do some sh!t

}

return YES;
}

- (BOOL)shouldAutorotate {

UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];

if (orientation==UIInterfaceOrientationPortrait) {
 // do some sh!t

}

return YES;
}

지원되는 방향은 info.plist에서 다음과 같이 지정할 수 있습니다. 지원되는 방향 pic

또는 코드 사용 :

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait; // etc
}

편집 : 다시 생각하면, 6.0뿐만 아니라 하위 버전 (iOS4.3 / 5 / 5.1)을 지원할 계획이라면 동일한 코드 콘텐츠를 가진 두 메서드를 모두 포함하십시오. 나를 위해 작동합니다 (어쨌든 sim에서)


앱 창 경로 컨트롤러를 설정하는 대신 하위보기로보기를 추가하는 대신 (Rocotilos가 한 것처럼)

//    [self.window addSubview:self.topLevelNavigationController.view];
self.window.rootViewController = self.topLevelNavigationController;

다음은 논리를 복제하지 않는 iOS 5 및 이전 코드에 대한 솔루션입니다. 이 코드를 뷰 컨트롤러에 추가하기 만하면 기존 shouldAutorotateToInterfaceOrientation 메서드에서 supportedInterfaceOrientations가 생성됩니다.

-(BOOL)shouldAutorotate{
    return YES;
}

-(NSInteger)supportedInterfaceOrientations{
NSInteger mask = 0;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationLandscapeRight])
    mask |= UIInterfaceOrientationMaskLandscapeRight;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationLandscapeLeft])
    mask |= UIInterfaceOrientationMaskLandscapeLeft;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationPortrait])
    mask |= UIInterfaceOrientationMaskPortrait;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationPortraitUpsideDown])
    mask |= UIInterfaceOrientationMaskPortraitUpsideDown;
return mask;
}

나를위한 빠른 수정은 루트 뷰 컨트롤러에이 코드를 추가하는 것이 었습니다.

- (BOOL)shouldAutorotate {
    return [self shouldAutorotateToInterfaceOrientation:self.interfaceOrientation];
}

이런 식으로 iOS 6 이전 버전에 사용 된 것과 동일한 논리를 계속 사용합니다. 물론, 원래는 Windows 하위보기에 추가하는 대신에 내 앱 위임 didFinishLaunchingWithOptions에서 내 rootViewController를 올바르게 설정했습니다.


그리고 많은 응답에 iOS 6 빌드에 shouldAutorotate 및 supportedInterfaceOrientations를 구현하는 솔루션이 표시되어 있지만 뷰 컨트롤러가 내비게이션 컨트롤러에서 호스팅되는 경우 아무 것도 중요하지 않습니다. 런타임은 UINavigationController 인스턴스에서이를 호출하고 그렇지 않으면 코드를 무시합니다.

분명히 '솔루션'은 UINavigationController를 하위 클래스로 만들고 여기에 설명 된 대로이 하위 클래스에서 이러한 새 메서드를 구현하는 것입니다. iOS 6 UITabBarController는 현재 UINavigation 컨트롤러에서 방향을 지원합니다.

그런 다음 UINavigationController를 사용하여이 새로운 하위 클래스를 대신 사용하는 모든 코드를 변경하는 즐거움을 누릴 수 있습니다.

이것은 내가 본 iOS 릴리스에서 가장 무의미하고 성가신 주요 변경 사항 중 하나 여야합니다.


IOS 5

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
if (UIInterfaceOrientationLandscapeLeft) {
        return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
    }
    if (UIInterfaceOrientationLandscapeRight) {
        return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
    }
    return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

IOS 6

-(BOOL)shouldAutorotate{
    return YES;
}

-(NSInteger)supportedInterfaceOrientations:(UIWindow *)window{

    //    UIInterfaceOrientationMaskLandscape;
    //    24
    //
    //    UIInterfaceOrientationMaskLandscapeLeft;
    //    16
    //
    //    UIInterfaceOrientationMaskLandscapeRight;
    //    8
    //
    //    UIInterfaceOrientationMaskPortrait;
    //    2


    //    return UIInterfaceOrientationMaskLandscape;
    return 24;
}

이것은 iOS6 및 Xcode 4.5 GM에서 저에게 효과적이었습니다.

AppDelegate.m에서

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    .....

    //   self.window.rootViewController = self.navigationController;

    [window setRootViewController:navigationController];

    .....

    return YES;
}

ViewController :

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration

{
    if (UIInterfaceOrientationIsLandscape(interfaceOrientation))

    {
      // landscape
    }
    else
    {
      //portrait
    }
}

다음은 Apple의 iOS SDK 인 XCode4.5 +의 인용문입니다 (UIViewController 클래스 참조, 뷰 회전 처리 참조).

iOS 6에서 앱은 앱의 Info.plist 파일에 정의 된 인터페이스 방향을 지원합니다. 뷰 컨트롤러는 supportedInterfaceOrientations 메서드를 재정 의하여 지원 되는 방향 목록을 제한 할 수 있습니다 . 일반적으로 시스템 은 창의 루트 뷰 컨트롤러 또는 전체 화면을 채우기 위해 제공된 뷰 컨트롤러 에서만 이 메서드를 호출합니다 . 자식 뷰 컨트롤러는 부모 뷰 컨트롤러가 제공하는 창 부분을 사용하며 지원되는 회전에 대한 결정에 더 이상 직접 참여하지 않습니다.

또한 iOS6에서 shouldAutorotateToInterfaceOrientation : UIViewController 클래스의 메서드는 이미 사용되지 않습니다.

따라서 루트 뷰 컨트롤러에서 ff를 수행합니다.

- (BOOL)shouldAutorotate {
  return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
  return UIInterfaceOrientationMaskPortrait;
}

Btw, "루트 뷰 컨트롤러"는 appDelegate 개체 rootViewController설정 한 UIViewController 하위 클래스 입니다. 일반적으로 appDelegate의 application : didFinishLaunchingWithOptions : 메소드 에서이 작업을 수행합니다 .

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  // Override point for customization after application launch.
  self.window.rootViewController = [FFDashboardController create];
  [self.window makeKeyAndVisible];
  return YES;
}

UINavigationController를 루트 VC로 사용하려면 Vladimir의 답변을 확인하십시오 .


@Rocotilos에 대한 응답으로 포럼의 다른 곳에서는 볼 수없는 내 코드에서 발생한 부록이 있습니다. 앱 수명주기의 맨 처음에 shouldAutorotate 메서드에서 방향이 알려지지 않은 상황이 발생했습니다. 이로 인해 앱이 가로로보기를 제대로 표시하지 못했습니다. 시뮬레이터에서 몇 번 회전 한 후 제대로 작동했습니다.

내 시나리오는 가로 레이아웃을 원하는 위치에 팝업되는 특정 뷰가 있다는 것입니다. 따라서 shouldAutorotate가 YES를 반환하는 것을 원하지 않습니다. 나는 이것이 일부에게는 드문 경우 일 수 있음을 알고 있지만 이것을 진단하는 데 많은 시간을 보냈으며 전달하고 싶었습니다. 이것이 도움이되기를 바랍니다.

- (BOOL) shouldAutorotate {

    BOOL shouldRotate = NO;
    UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];

    if ([self IsCaseWhereWeDontWantLandscapeAutorotation]) {
        shouldRotate = NO;
    } else if (orientation == UIDeviceOrientationUnknown) {
        //Handle the case where the device's orientation is not yet known
        shouldRotate = YES;
    } else {
        //Handle the normal case
        shouldRotate = (orientation == UIInterfaceOrientationMaskLandscape);
    }

    return shouldRotate;
}

루트 뷰만이 이러한 호출을 처리한다는 것이 밝혀졌습니다. 제 경우에는 정상적인 UINavigationController였습니다. 메서드를 추가 한 하위 클래스 파일로 변경해야했습니다.

제 경우에는 루트 뷰 초상화 만 원했고 나머지는 초상화 + 풍경 만 원했습니다.

Appdelegate.h

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    S2MBookAppRootViewController *masterViewController = [[[S2MBookAppRootViewController alloc] initWithNibName:pref.rootNibName bundle:nil] autorelease];
    self.navigationController = [[[S2MBookAppNavController alloc] initWithRootViewController:masterViewController] autorelease];

    self.window.rootViewController = self.navigationController;


    [self.window makeKeyAndVisible];
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:YES];

    return YES;
}

그리고 S2MBookAppNavController (UINavigationController의 하위 클래스)

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    if([self.viewControllers count] == 1) return UIInterfaceOrientationMaskPortrait;
    return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscape;
}

업데이트 : 방향을 강제하고 싶을 때 (내비게이션 컨트롤러에서 새 뷰를 푸시 할 때) 이것을 시도하십시오.

UINavigationController도 자체 대리자로 만듭니다.

@interface S2MBookAppNavController : UINavigationController <UINavigationControllerDelegate>

@end

그리고 .m 파일에서

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.delegate = self;
    // Do any additional setup after loading the view.
}

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
        if ([UIViewController respondsToSelector:@selector(attemptRotationToDeviceOrientation)]) {
            //present/dismiss viewcontroller in order to activate rotating.
            UIViewController *mVC = [[[UIViewController alloc] init] autorelease];
            [self presentModalViewController:mVC animated:NO];
            [self dismissModalViewControllerAnimated:NO];
        }
}

Yes, problem is only window.rootViewController method called to return orientation mask. So supportedInterfaceOrientations method must be implemented in viewController which is set as window.rootViewController. But in most cases this object is not of custom class, e.g. UINavigationController. One possible solution is to subclass UINavigationController. But Apple says: "This class is not intended for subclassing", so I'd rather used another UIViewController to handle orientations and added UINavigationController as child.

MyRootViewController * myRoot = [MyRootViewController new];
self.window.rootViewController = myRoot;
[myRoot addChildViewController:navigationController];
[myRoot.view addSubview:navigationController.view];

and in MyRootViewController implement methods:

- (BOOL)shouldAutorotate {
 return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    // return your mask here e.g.:
    return UIInterfaceOrientationMaskPortrait;
}

I have a series of view controllers in a UINavigationController, one of which had to be landscape only. I fixed it by subclassing the UINavigationController and adding the following code:

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

This ensures that the topmost view controller dictates the orientation.

There is a gotcha, though: if you are moving from a vc that is limited to landscape to one that supports any orientation, the new view will display in landscape regardless of the phone's orientation. To combat this, I put the following code in the unlimited viewControllers:

- (NSUInteger)supportedInterfaceOrientations{
   if(UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]))       
      return UIInterfaceOrientationMaskPortrait;
   else
      return UIInterfaceOrientationMaskLandscape;
}

-(BOOL)shouldAutorotate
{
    UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;

    if (orientation == UIDeviceOrientationUnknown) {
        return YES;
    }

    return [self shouldAutorotateToInterfaceOrientation:self.interfaceOrientation];
}

The notes under the heading UIKit here: http://developer.apple.com/library/ios/#releasenotes/General/RN-iOSSDK-6_0/_index.html%23//apple_ref/doc/uid/TP40012166-CH1-SW19 give some clues to the answer, but it is not the whole picture. I don't have the whole picture yet, but here is what I have found so far for iOS 6.0 RTM.

If you are not really restricting the supported orientations and, instead, you are wanting to do something because the user rotated the device, then you can move the logic in

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

to

- (void)viewWillLayoutSubviews

instead.

This can probably be a direct replacement, but I have not tested in down level iOS versions yet.

If you want to restrict the supported orientations, you should do that at the UIApplicationDelegate level with

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window

The documentation states that "The system determines whether an orientation is supported by intersecting the value returned by the app’s supportedInterfaceOrientationsForWindow: method with the value returned by the supportedInterfaceOrientations method of the top-most full-screen controller." but in experimentation I have found that the system ignores my view controllers supported

-(NSUInteger)supportedInterfaceOrientations

return value, even though the method is called.


Apple은 ios6에서 shouldautorate 메소드를 사용하지 않고 대신 이러한 메소드를 사용합니다. xcode 문서보기

- (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0);
- (NSUInteger)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0);
// Returns interface orientation masks.
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation NS_AVAILABLE_IOS(6_0);

나를 위해 일하는 것 :

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    NSUInteger orientations = UIInterfaceOrientationMaskPortrait;
    if ([self isKindOfClass:[YourViewController class]]) { // Your view class
        orientations |= UIInterfaceOrientationMaskPortraitUpsideDown;
    }
    return orientations;
}

방향 :

orientations |= UIInterfaceOrientationMaskLandscapeLeft;
orientations |= UIInterfaceOrientationMaskLandscapeRight;

참고 URL : https://stackoverflow.com/questions/12260261/shouldautorotatetointerfaceorientation-not-being-called-in-ios-6

반응형