Appleからガジェット用のアプリケーションを作成している場合は、おそらくiOSが最近バージョン6に更新されていることをご存じでしょう。
Appleは他の新機能とともに、自動回転メカニズムに変更を加えました。
念のために、自動回転は、デバイスを縦(細長い)および横(拡張)の両方の方向で使用できるメカニズムであり、デバイスを回転させるときにこの方向を変更できることを思い出させてください。

アプリケーションが両方の方向にコンテンツを表示する場合(特に一部の画面で回転を禁止する必要がある場合)-すでにいくつかの質問があります。
画面の向きの変更機能を使用しない場合、違いに気付かない場合があります。 ただし、iOS6で自動回転がどのように機能するかを理解することは、いずれにしても将来的には有用で便利になります。
iOS 6以前のように
IOSデバイスは、対応するシステム定数によって記述される4つの可能な画面の向きをサポートします。
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationPortraitUpsideDown
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
iOS 5以前では、自動回転メカニズムはメソッドを使用します
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // YES return (interfaceOrientation == UIInterfaceOrientationPortrait); }
このメソッドを呼び出すことにより、デバイスが空間内で向きを変更すると、システムはアクティブなコントローラー(View Controller)にこの向きへの移行をサポートするかどうかを尋ねます。
メソッドを呼び出すとき、interfaceOrientationパラメーターには4つの可能な値のいずれかが含まれ、メソッドはアプリケーションウィンドウを回転する場合はYES(そうでない場合はNO)を返す必要があります。
したがって、個々のコントローラーごとにshouldAutorotateToInterfaceOrientation:メソッドを再定義し、それによってサポートされる方向のタイプを指定するだけで十分です。
Info.plistのUISupportedInterfaceOrientationsキーには、アプリケーションでサポートされている方向のリストが含まれ(ターゲットの[概要]セクションで選択することもできます)、アプリケーションの起動時に初期方向を決定するためにのみシステムによって使用されます。


方向が指定されていない場合、問題は発生せず、アプリケーションは通常のポートレートモード(UIInterfaceOrientationPortrait)で起動されます。
iOS 6で
iOS 6では、 shouldAutorotateToInterfaceOrientationメソッドは非推奨になり、 自動回転のロジックはsupportedInterfaceOrientationsとshouldAutorotateの 2つが原因です。
デバイスの位置を変更するとき(またはコントローラーがモーダルで表示されるとき)、システムは最上部のフルスクリーンビューコントローラーをポーリングします。 最初にshouldAutorotateの呼び出しが発生し 、次に(値YESが返された場合のみ)、 supportedInterfaceOrientationsの呼び出しが呼び出されて、サポートされる位置を記述するビットマスクが取得されます。 たとえば、次のコードを使用して、通常の縦向きと横向きの両方をサポートできます。
- (NSInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight; }
さらに、システムはsupportedInterfaceOrientationsから取得した値を使用して、アプリケーションによってグローバルにサポートされている方向のリスト(Info.plistから、またはAppDelegate アプリケーションの結果としてsupportedInterfaceOrientationsForWindow:メソッド) との組み合わせ演算(ビット単位AND)を実行します 。 操作の結果によると、ターンがあります(またはありません)。
要するに、決定は操作によって行われます
app_mask & topmost_controller_mask
app_maskはInfo.plist( application:supportedInterfaceOrientationsForWindow :)から取得され、トップフルスクリーンコントローラーのsupportedInterfaceOrientationsを呼び出した結果としてtopmost_controller_maskが取得されます。
次の点も考慮する必要があります。
- app_maskの値はグローバルであるため、慎重に変更する必要があります
- 一時的に回転機能を無効にするには、 supportedInterfaceOrientationsでマスクを操作するのではなく、 shouldAutorotateを使用することをお勧めします。
- application:supportedInterfaceOrientationsForWindow:メソッドがAppDelegateで使用されている場合、Info.plistの値は無視されます
- ある時点で結合の結果が0の場合、 UIApplicationInvalidInterfaceOrientationExceptionがスローされます
- supportedInterfaceOrientationsメソッドとshouldAutorotateメソッドを再定義していない場合、コントローラーはデフォルトでiPadデバイスとiPhoneでPortraitUpsideDownを除くすべての方向タイプをサポートします
- 新しいpreferredInterfaceOrientationForPresentationメソッドを使用すると、コントローラーが表示されるときのコントローラーの優先方向を指定できます。
- shouldAutoRotateToInterfaceOrientation: iOS 6では呼び出されなくなりましたが、以前のバージョンのiOSを搭載したデバイスをサポートするために引き続き使用する必要があります
これらは変更点です。 この動きは、サポートされている画面の位置に関する決定を下す責任を、特定のアクティブな各コントローラーからコンテナーコントローラーとアプリケーション自体に移したいというAppleの要望によって決まります。
このテーマに関するAppleの重要な考え(WWDC 2012のセッション236)は次のとおりです。
- コントローラーは、可能なすべてのモードをサポートするよう努力する必要があります
- 子コントローラーは、親によって指定されたフレームに表示できる必要があります
- アプリケーションは、サポートされている方向タイプを指定できる必要があります(Info.plistまたはapplication:supportedInterfaceOrientationsForWindow :)
- 回すと、ルートまたはトップフルスクリーンコントローラーのみがポーリングされます
それをどうするか
iOS 5以前のサポートを必要とする新しいプロジェクトを開発する場合、AppleはiOS 6のメカニズムをエミュレートすることをお勧めします。
- ルートまたはフルスクリーンコントローラーでサポートされる画面の向きの完全なリストを指定する
- 子コントローラーで必要なすべての方向のサポートを実装する
ただし、異なるエンドコントローラーによってターンに関する決定が行われる既存のプロジェクトをiOS 6に(できれば最小限の労力で)移行する必要がある場合はどうすればよいでしょうか? shouldAutorotateToInterfaceOrientationの横にある新しいsupportedInterfaceOrientations / shouldAutorotateメソッドを使用しても、これらのコントローラーがルートおよび最上部のフルスクリーンでない場合、状況は保存されません。 コンテナーコントローラーが制御されたコンテナーの意見を聞くようにするには、次のアプローチを使用できます。
1.カテゴリー。
カテゴリを使用して、新しいメソッドを再定義して、対応するトップコントローラーに回転を問い合わせます。 たとえば、UINavigationControllerの場合、これは次のようになります。
@implementation UINavigationController (RotationIOS6) -(BOOL)shouldAutorotate { return [self.topViewController shouldAutorotate]; } -(NSUInteger)supportedInterfaceOrientations { return [self.topViewController supportedInterfaceOrientations]; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return [self.topViewController preferredInterfaceOrientationForPresentation]; } @end
2.継承。
パラグラフ1と同じように実装しますが、UINavigationControllerから継承することにより、すべてのUINavigationControllerを一度にグローバルに変更する必要がない場合。
// CustomNavigationController.h @interface CustomNavigationController : UINavigationController @end
// CustomNavigationController.m #import "CustomNavigationController.h" @implementation CustomNavigationController -(BOOL)shouldAutorotate { return [self.topViewController shouldAutorotate]; } -(NSUInteger)supportedInterfaceOrientations { return [self.topViewController supportedInterfaceOrientations]; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return [self.topViewController preferredInterfaceOrientationForPresentation]; } @end
3.メソッドのスウィズリング。
ランタイム愛好家や筋金入りのファンの場合、 スウィズルを使用して、新しいメソッドを再定義して、古いおなじみのメソッドshouldAutorotateToInterfaceOrientation:の呼び出しを実際に使用します。
( ここから取られたコード)
@implementation AppDelegate void SwapMethodImplementations(Class cls, SEL left_sel, SEL right_sel) { Method leftMethod = class_getInstanceMethod(cls, left_sel); Method rightMethod = class_getInstanceMethod(cls, right_sel); method_exchangeImplementations(leftMethod, rightMethod); } + (void)initialize { if (self == [AppDelegate class]) { #ifdef __IPHONE_6_0 SwapMethodImplementations([UIViewController class], @selector(supportedInterfaceOrientations), @selector(sp_supportedInterfaceOrientations)); SwapMethodImplementations([UIViewController class], @selector(shouldAutorotate), @selector(sp_shouldAutorotate)); #endif } } @end @implementation UIViewController (iOS6Autorotation) #ifdef __IPHONE_6_0 /* * We've swizzled the new iOS 6 autorotation callbacks onto their iOS 5 and iOS 4 equivalents * to preserve existing functionality. * */ - (BOOL)sp_shouldAutorotate { BOOL shouldAutorotate = YES; if ([self respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) { NSUInteger mask = 0; if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait]) { mask |= UIInterfaceOrientationMaskPortrait; } if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeLeft]) { mask |= UIInterfaceOrientationMaskLandscapeLeft; } if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeRight]) { mask |= UIInterfaceOrientationMaskLandscapeRight; } if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortraitUpsideDown]) { mask |= UIInterfaceOrientationMaskPortraitUpsideDown; } if (mask == 0) { // Shouldn't autorotate to *any* orientation. shouldAutorotate = NO; } } else { // This actually calls the original method implementation // instead of recursively calling into this method implementation. shouldAutorotate = [self sp_shouldAutorotate]; } return shouldAutorotate; } - (NSUInteger)sp_supportedInterfaceOrientations { NSUInteger mask = 0; /* * In iOS 6, Apple dramatically changed the way autorotation works. * Rather than having each view controller respond to shouldAutorotateToInterfaceOrientation: * to specify whether or not it could support a particular orientation, the responsibility was * shifted to top-level container view controllers. That means UINavigationController becomes * responsible for declaring whether or not an orientation is supported. Since our app * has logic for how to autorotate on a per view controller basis, we call through to the * swizzled version of supportedInterfaceOrientations for the topViewController. * */ if ([self isKindOfClass:[UINavigationController class]]) { return [[(UINavigationController *)self topViewController] supportedInterfaceOrientations]; } if ([self respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) { if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait]) { mask |= UIInterfaceOrientationMaskPortrait; } if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeLeft]) { mask |= UIInterfaceOrientationMaskLandscapeLeft; } if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeRight]) { mask |= UIInterfaceOrientationMaskLandscapeRight; } if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortraitUpsideDown]) { mask |= UIInterfaceOrientationMaskPortraitUpsideDown; } } else { // This actually calls the original method implementation // instead of recursively calling into this method implementation. mask = [self sp_supportedInterfaceOrientations]; } return mask; } #endif @end
この場合、既存のコードを変更する必要はまったくありません。ランタイムの魔法がその役割を果たします。 しかし、どんなに魅力的であっても、 このコードは使用することをお勧めしません (理由を確認してください) 。
私の場合、カテゴリを使用するのが最も便利でした。
提示された資料が誰かにとって有用であり、開発者の最も貴重なリソースの節約に役立つことを願っています-時間:)
便利なリンク: