これは、人々が私にガイダンスを提供するためのより一般的な質問であり、基本的にはiPad/iPhoneの開発を学び、ついに多方向サポートの質問に出くわしました。
私はかなりの数のdocoを調べましたが、私の著書「Beginning iPhone 3 Development」には素敵な章があります。
しかし、私の質問はこれです。プログラムでプログラムの制御を変更した場合(または方向ごとに異なるビューを使用した場合)は、いったいどのように人々がコードベースを維持するのでしょうか。いたるところにスパゲッティコード/何千もの "if"チェックに関する多くの問題が想像できるので、UIの配置に小さな変更を1つ加えるのは大変です。
誰かがこの問題を処理した経験がありますか?それを制御する良い方法は何ですか?
どうもありがとうMark
私はビューコントローラーで2つの単純なメソッドを使用してこれを行います。
- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[self adjustViewsForOrientation:toInterfaceOrientation];
}
- (void) adjustViewsForOrientation:(UIInterfaceOrientation)orientation {
if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
titleImageView.center = CGPointMake(235.0f, 42.0f);
subtitleImageView.center = CGPointMake(355.0f, 70.0f);
...
}
else if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
titleImageView.center = CGPointMake(160.0f, 52.0f);
subtitleImageView.center = CGPointMake(275.0f, 80.0f);
...
}
}
これをきれいに保つために、ビューの調整/再読み込みなどを簡単に区分化できます。単一のif-else
条件付きの内部から呼び出されるメソッドを使用します。
それは本当にあなたが何をレイアウトしているかに依存します。
Apple設定アプリケーションを見ると、ほとんどの行にカスタムセルを使用して、レイアウトにテーブルビューを使用していることがわかります。これにより、シンプルなインターフェイスを非常に安価に回転させることができます。セルの幅を塗りつぶすだけです。これは、各行に編集テキストセルがあるMailなどにも当てはまります。また、ボタンやラベルのみが表示されているため、テーブルを簡単にすべて透明にして、テーブルのように見せることはできません。
すべてのUIViewのautoresizingMaskから多くの距離を得ることができます。柔軟な高さを持つことができる1つ以上のアイテムがある場合、通常はどちらの方向でも見栄えの良いインターフェイスレイアウトを取得できます。外観によっては、すべてを上に固定することもできます。
まれに、すべてのインターフェース要素が正方形に収まる場合は、それらを所定の位置に回転させることができます。
方向の変更を明示的に処理する必要がある場合が2つあります。 1つは、回転時にビューが別の横から下に移動するときです。もう1つは、たとえば常に全幅にしたい場合など、向きごとに異なる画像がある場合です。
これらの両方を回避する方法が時々あります。伸縮可能な画像を使用するか、1行に1つのビューに制限することができます。または、特定のビューの向きをロックアウトする場合があります。
ビューのレイアウトを変更する必要がある場合は、明示的なlayoutSubviewsメソッドがあります。この1つの方法では、条件付きレイアウトをすべて処理する必要があります。これは、回転などでビューの境界が変更されたとき、またはキーボード用のスペースを空けたときにのみ呼び出されます。回転に応答する必要がある各ビュー階層のカスタムビューを作成し、そこからサブビューをレイアウトします。
IPhone SDKはMVCアーキテクチャを中心に構築されているため、理論的には、すべてのロジック(モデル)をUI(ビュー)から分離しておけば、ビューコントローラーという1つの場所でUIについて心配するだけで済みます。それらの場合、方向ごとに個別のビューコントローラーを用意し、それぞれに1つのif/elseをロードするだけで、ロードするビューコントローラーを選択できます。
同じ考え方がiPhone/iPadのサポートにも当てはまり、より大きなディスプレイを処理できる別のView Controllerをロードできます。
私はこのコードを保証することはできません。正直に言って、上記のwillRotateToInterfaceOrientationは非常にうまく機能します。 Facebook/iPhone/iPad用のFBDialog.mを使用した別の例を次に示します。 (とはいえ、これはウェブビュー用だったと思います)
ここに要点があります
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(deviceOrientationDidChange:)
name:@"UIDeviceOrientationDidChangeNotification" object:nil];
- (void)deviceOrientationDidChange:(void*)object {
UIDeviceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if ([self shouldRotateToOrientation:orientation]) {
CGFloat duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
[self sizeToFitOrientation:YES];
[UIView commitAnimations];
}
}
-(CGAffineTransform)transformForOrientation {
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (orientation == UIInterfaceOrientationLandscapeLeft) {
return CGAffineTransformMakeRotation(M_PI*1.5);
} else if (orientation == UIInterfaceOrientationLandscapeRight) {
return CGAffineTransformMakeRotation(M_PI/2);
} else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
return CGAffineTransformMakeRotation(-M_PI);
} else {
return CGAffineTransformIdentity;
}
}
- (void)sizeToFitOrientation:(BOOL)transform {
if (transform) {
self.transform = CGAffineTransformIdentity;
}
CGRect frame = [UIScreen mainScreen].applicationFrame;
CGPoint center = CGPointMake(
frame.Origin.x + ceil(frame.size.width/2),
frame.Origin.y + ceil(frame.size.height/2));
CGFloat scale_factor = 1.0f;
if (FBIsDeviceIPad()) {
// On the iPad the dialog's dimensions should only be 60% of the screen's
scale_factor = 0.6f;
}
CGFloat width = floor(scale_factor * frame.size.width) - kPadding * 2;
CGFloat height = floor(scale_factor * frame.size.height) - kPadding * 2;
_orientation = [UIApplication sharedApplication].statusBarOrientation;
if (UIInterfaceOrientationIsLandscape(_orientation)) {
self.frame = CGRectMake(kPadding, kPadding, height, width);
} else {
self.frame = CGRectMake(kPadding, kPadding, width, height);
}
self.center = center;
if (transform) {
self.transform = [self transformForOrientation];
}
}
あなたの質問では、あなたは書きました:
いたるところにスパゲッティコード/何千もの「if」チェックに関する多くの問題が想像できますが、UIの配置に1つの小さな変更を加えるのは大変です。
これを回避する1つの方法は、iPhone/iPad固有の変更の処理を最初から分割するビュー階層を作成することです。デバイスごとに最初にロードするビューを設定するだけで済みます。次に、通常のようにビューコントローラーを作成しますが、作成したビューコントローラーもサブクラス化します。デバイスごとに1つのサブクラス。ここで、向きの処理など、デバイス固有のコードを配置できます。このような:
MyViewController.h // Code that is used on both devices
MyViewController_iPhone.h // iPhone specific code, like orientation handling
MyViewController_iPad.h // iPad specific code, like orientation handling
このアプローチに興味があるなら、 この記事 を読むことをお勧めします。それはとても素敵な方法で説明しています。
この記事で言及していることの1つは次のとおりです。
-引用の開始-
このパターンの利点は、次のようながらくたでコードを散らかす必要がないことです。
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// The device is an iPad running iPhone 3.2 or later.
// set up the iPad-specific view
} else {
// The device is an iPhone or iPod touch.
// set up the iPhone/iPod Touch view
}
---引用の終わり-
お役に立てば幸いです。幸運を!