以前のバージョンのiOSで古いデバイスとの互換性を維持しながら、iOS 6の新しい自動レイアウト機能を利用する最良の方法は何ですか?
以前のバージョンのiOSで古いデバイスとの互換性を維持しながら、iOS 6の新しい自動レイアウト機能を利用する最良の方法は何ですか?
回答:
自動レイアウトは、各.storyboardファイルまたは.xibファイルで有効または無効にできます。特定のファイルを選択し、Xcodeのファイルインスペクタを使用して[Autolayoutを使用]プロパティを変更するだけです。
展開ターゲットが6.0より前のiOSバージョンに設定されたautolayout対応のインターフェースファイルを使用すると、コンパイルエラーが発生します。例:
MainStoryboard.storyboard:3のエラー:6.0より前のiOSバージョンでの自動レイアウト
プロジェクトでautolayoutを使用し、iOS4-5との互換性を維持するためのオプションの1つは、2つのターゲットを作成することです。1つはデプロイメントターゲットiOS 6.0用で、もう1つは以前のiOSバージョン用です。例:
ストーリーボードとXIBファイルのそれぞれに2つのバージョンを作成し、6.0ターゲットで有効になっているオートレイアウトとレガシーターゲットでもう1つを使用することができます。例:
次に、MainStoryBoardAutoSizeをiOS6ターゲットのビルドフェーズに追加し、他のファイルをiOS4ターゲットに追加します。複数のターゲットの使用について詳しくは、こちらをご覧ください。
編集:marchinramの回答が指摘しているように、コードからストーリーボードファイルをロードし、Xcodeの「メインストーリーボード」設定を使用して初期ストーリーボードを設定しない場合、単一のターゲットを使用できます。
私にとっては、複数のターゲットとインターフェースファイルを維持するために追加される複雑さのコストが、自動レイアウトを使用するメリットを上回るようです。いくつかの特別な場合を除いて、iOS4-5の互換性が必要な場合は、通常の自動サイズ調整(またはコードのlayoutSubViews)のみを使用する方がはるかに良いでしょう。
本当に2つのターゲットが必要ですか?私はそれをこのように機能させています、ImreKelényiが言ったように2つのストーリーボードがあります.1つは自動レイアウトが有効で、もう1つは有効ではありません。アプリのデリゲートで、使用しているバージョンを確認し、適切なストーリーボードを選択します:
#import "AppDelegate.h"
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:(v) options:NSNumericSearch] != NSOrderedAscending)
@interface AppDelegate ()
@property (strong, nonatomic) UIViewController *initialViewController;
@end
@implementation AppDelegate
@synthesize window = _window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIStoryboard *mainStoryboard = nil;
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"6.0")) {
mainStoryboard = [UIStoryboard storyboardWithName:@"iPhone_iOS6" bundle:nil];
} else {
mainStoryboard = [UIStoryboard storyboardWithName:@"iPhone_iOS5" bundle:nil];
}
self.initialViewController = [mainStoryboard instantiateInitialViewController];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = self.initialViewController;
[self.window makeKeyAndVisible];
return YES;
}
@end
2つのターゲットを持つことも同様に機能しますが、私にはやり過ぎのようです
SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO
やりすぎです。iOS 6のみのクラスをnilに対してテストするだけです。developer.apple.com/library/mac/#documentation/developertools/…を
レイアウトの違いが大きくない場合は、SpringsとStrutsを使用して要素を配置する方がはるかに簡単です。
@marchinramの1つのターゲットアイデアに触発された、これが私が最終的に思いついたソリューションです。2つのストーリーボード。1つは支柱とばね用、もう1つは自動レイアウト用です。ターゲットの概要では、autolayoutストーリーボードをデフォルトとして設定しました。次に、appDelegateで、6.0より前のstruts-and-springsストーリーボードをロードする必要があるかどうかを確認します。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
Class cls = NSClassFromString (@"NSLayoutConstraint");
if (cls == nil) {
NSString *mainStoryboardName = nil;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
mainStoryboardName = @"MainStoryboard_iPad_StrutsAndSprings";
} else {
mainStoryboardName = @"MainStoryboard_iPhone_StrutsAndSprings";
}
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:mainStoryboardName bundle:nil];
UIViewController *initialViewController = [mainStoryboard instantiateInitialViewController];
self.window.rootViewController = initialViewController;
[self.window makeKeyAndVisible];
}
また、struts-and-springsストーリーボードの展開ターゲットをiOS 5.1に設定し、autolayoutストーリーボードの展開ターゲットをProject SDK(iOS 6.0)に設定しました。
ストーリーボードのデフォルトが読み込まれる前に、willFinishLaunchingWithOptionsで切り替えを実行したかったのですが、結果は 'NSInvalidUnarchiveOperationException'になります。理由: '何を試してもNSLayoutConstraintという名前のクラスをインスタンス化できませんでした。
RRAutoLayoutを使用してみてください:https : //github.com/RolandasRazma/RRAutoLayout これは、iOS5 AutoLayoutのiOS5へのバックポートです。