web-dev-qa-db-ja.com

iPhone / iPadの向きの処理

これは、人々が私にガイダンスを提供するためのより一般的な質問であり、基本的にはiPad/iPhoneの開発を学び、ついに多方向サポートの質問に出くわしました。

私はかなりの数のdocoを調べましたが、私の著書「Beginning iPhone 3 Development」には素敵な章があります。

しかし、私の質問はこれです。プログラムでプログラムの制御を変更した場合(または方向ごとに異なるビューを使用した場合)は、いったいどのように人々がコードベースを維持するのでしょうか。いたるところにスパゲッティコード/何千もの "if"チェックに関する多くの問題が想像できるので、UIの配置に小さな変更を1つ加えるのは大変です。

誰かがこの問題を処理した経験がありますか?それを制御する良い方法は何ですか?

どうもありがとうMark

34
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条件付きの内部から呼び出されるメソッドを使用します。

41
Alex Reynolds

それは本当にあなたが何をレイアウトしているかに依存します。

Apple設定アプリケーションを見ると、ほとんどの行にカスタムセルを使用して、レイアウトにテーブルビューを使用していることがわかります。これにより、シンプルなインターフェイスを非常に安価に回転させることができます。セルの幅を塗りつぶすだけです。これは、各行に編集テキストセルがあるMailなどにも当てはまります。また、ボタンやラベルのみが表示されているため、テーブルを簡単にすべて透明にして、テーブルのように見せることはできません。

すべてのUIViewのautoresizingMaskから多くの距離を得ることができます。柔軟な高さを持つことができる1つ以上のアイテムがある場合、通常はどちらの方向でも見栄えの良いインターフェイスレイアウトを取得できます。外観によっては、すべてを上に固定することもできます。

まれに、すべてのインターフェース要素が正方形に収まる場合は、それらを所定の位置に回転させることができます。

方向の変更を明示的に処理する必要がある場合が2つあります。 1つは、回転時にビューが別の横から下に移動するときです。もう1つは、たとえば常に全幅にしたい場合など、向きごとに異なる画像がある場合です。

これらの両方を回避する方法が時々あります。伸縮可能な画像を使用するか、1行に1つのビューに制限することができます。または、特定のビューの向きをロックアウトする場合があります。

ビューのレイアウトを変更する必要がある場合は、明示的なlayoutSubviewsメソッドがあります。この1つの方法では、条件付きレイアウトをすべて処理する必要があります。これは、回転などでビューの境界が変更されたとき、またはキーボード用のスペースを空けたときにのみ呼び出されます。回転に応答する必要がある各ビュー階層のカスタムビューを作成し、そこからサブビューをレイアウトします。

7
drawnonward

IPhone SDKはMVCアーキテクチャを中心に構築されているため、理論的には、すべてのロジック(モデル)をUI(ビュー)から分離しておけば、ビューコントローラーという1つの場所でUIについて心配するだけで済みます。それらの場合、方向ごとに個別のビューコントローラーを用意し、それぞれに1つのif/elseをロードするだけで、ロードするビューコントローラーを選択できます。

同じ考え方がiPhone/iPadのサポートにも当てはまり、より大きなディスプレイを処理できる別のView Controllerをロードできます。

2
Winder
1
symadept

私はこのコードを保証することはできません。正直に言って、上記の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];
  }
}
0
johndpope

あなたの質問では、あなたは書きました:

いたるところにスパゲッティコード/何千もの「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
}

---引用の終わり-

お役に立てば幸いです。幸運を!

0
matsr