iOS 6の自動回転について

こんにちは友人!



Appleからガジェット用のアプリケーションを作成している場合は、おそらくiOSが最近バージョン6に更新されていることをご存じでしょう。

Appleは他の新機能とともに、自動回転メカニズムに変更を加えました。

念のために、自動回転は、デバイスを縦(細長い)および横(拡張)の両方の方向で使用できるメカニズムであり、デバイスを回転させるときにこの方向を変更できることを思い出させてください。

画像

アプリケーションが両方の方向にコンテンツを表示する場合(特に一部の画面で回転を禁止する必要がある場合)-すでにいくつかの質問があります。

画面の向きの変更機能を使用しない場合、違いに気付かない場合があります。 ただし、iOS6で自動回転がどのように機能するかを理解することは、いずれにしても将来的には有用で便利になります。



iOS 6以前のように



IOSデバイスは、対応するシステム定数によって記述される4つの可能な画面の向きをサポートします。



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メソッドは非推奨になり、 自動回転のロジックはsupportedInterfaceOrientationsshouldAutorotateの 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が取得されます。



次の点も考慮する必要があります。







これらは変更点です。 この動きは、サポートされている画面の位置に関する決定を下す責任を、特定のアクティブな各コントローラーからコンテナーコントローラーとアプリケーション自体に移したいというAppleの要望によって決まります。



このテーマに関するAppleの重要な考え(WWDC 2012のセッション236)は次のとおりです。





それをどうするか



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
      
      





この場合、既存のコードを変更する必要はまったくありません。ランタイムの魔法がその役割を果たします。 しかし、どんなに魅力的であっても、 このコードは使用することをお勧めしません (理由を確認してください)



私の場合、カテゴリを使用するのが最も便利でした。



提示された資料が誰かにとって有用であり、開発者の最も貴重なリソースの節約に役立つことを願っています-時間:)



便利なリンク:




All Articles