web-dev-qa-db-ja.com

複数の向きをサポートする最も簡単な方法は?アプリケーションが横向きのときにカスタムNIBをロードするにはどうすればよいですか?

複数の向きをサポートしたいアプリケーションがあります。使用したい2つの.xibファイルがあります。myViewController.xibとmyViewControllerLandscape.xib. myViewController.xibは、project/Resourcesにあり、myViewControllerLandscape.xibは、ルートプロジェクトディレクトリにあります。

私がやりたいのは、ローテーションに別のNIB (myViewControllerLandscape.xib)を使用することです。これをviewDidLoad likeで回転を検出してみます。

if((self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight))
 {
  NSLog(@"Landscape detected!");
  [self initWithNibName:@"myViewControllerLandscape" bundle:nil];

 }

しかし、gdbでは、デバイスが横向きの状態でアプリが起動されたときに実行されないことがわかります。 NSLogメッセージは発生しません。どうしてこれなの?何が悪いのでしょうか?

また、initWithNibName関数呼び出しをviewDidLoadメソッドに明示的に配置すると、そのnibはロードされず、myViewController.xibファイルで続行されます。私の電話の何が問題になっていますか?バンドルを指定する必要がありますか?

ありがとう!

35
Peter Hajas

1つのビューをロードしてから方向を確認し、必要に応じて別のビューをロードする必要があります。オリエンテーションはshouldAutorotateToInterfaceOrientation:回転したい場合はyesを返します。

ナビゲーションコントローラーを使用して遷移を管理します。ポートレートビューを上にしてデバイスが回転している場合は、ランドスケープビューをプッシュし、ポートレートに戻ったときにランドスケープビューをポップします。

編集:

ShouldAutorotateToInterfaceOrientationのすべての方向でYESを返します。ただし、アプリの起動時に呼び出されますか?あなたはこの機能の内側にあなたの見解をプッシュしますか?

方向定数は、照会するグローバルではなく、システムによってコントローラーに送信されるメッセージの一部です。そのため、ビューコントローラーが読み込まれる前に方向を簡単に検出することはできません。代わりに、特定の向き(通常は縦向き)で起動し、すぐに回転するようにアプリを配線します。 (モバイルSafariを参照してください。常に縦向きで始まり、その後横向きに回転します。)

これらは、ポートレートビューとランドスケープビューを入れ替えるために使用した2つの方法です。

3つのView Controllerすべてにこのメソッドがあります。

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

肖像画にはこれがあります:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

    if (toInterfaceOrientation==UIInterfaceOrientationLandscapeRight) {
        [self.nav pushViewController:rightLVC animated:NO];
    }
    if (toInterfaceOrientation==UIInterfaceOrientationLandscapeLeft) {
        [self.nav pushViewController:leftLVC animated:NO];
    }
}

各ランドスケープコントローラーにはこれがあります:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

    if (toInterfaceOrientation==UIInterfaceOrientationPortrait) {
        [self.nav popViewControllerAnimated:NO];
    }

アプリは縦向きで起動します。デバイスの向きが横向きの場合、適切な横向きがプッシュされます。デバイスが回転して縦向きに戻ると、横向きになります。ユーザーにとっては、同じビューが別の向きに再編成されているように見えます。

40
TechZen

Navコントローラーから独立して機能するはるかに良い方法を見つけました。現在、私はこれをnavコントローラーに埋め込んだとき、および埋め込まれていないときに機能しています(ただし、現在navコントローラーを使用していないため、見たことのないバグがある可能性があります。おかしい、または何か)

Appleの命名規則を使用した2つのNIB。 iOS 6または7では、Appleがこれを「機能」として追加する可能性があります。アプリで使用しており、完全に機能します。

  1. 回転ではなく、回転するトリガー(回転アニメーションが開始するまで待機する必要があります)
  2. Appleランドスケープ/ポートレートファイルの命名規則を使用します(必要な場合、Default.pngはDefault-landscape.pngですApple))
  3. 新しいNIBをリロードします
  4. self.viewをリセットします-これにより、表示が自動的に更新されます
  5. そして、それはviewDidLoadを呼び出します(手動でNIBを再ロードした場合、Appleはこれを呼び出しません)
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    if( UIInterfaceOrientationIsLandscape(toInterfaceOrientation) )
    {
        [[NSBundle mainBundle] loadNibNamed: [NSString stringWithFormat:@"%@-landscape", NSStringFromClass([self class])]
                                      owner: self
                                    options: nil];
        [self viewDidLoad];
    }
    else
    {
        [[NSBundle mainBundle] loadNibNamed: [NSString stringWithFormat:@"%@", NSStringFromClass([self class])]
                                      owner: self
                                    options: nil];
        [self viewDidLoad];
    }
}
59
Adam

本当にアダムの答えのように-ポートレートまたはランドスケープのいずれかでニブの初期読み込みを可能にするために少し修正しました

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    if( !nibNameOrNil )     nibNameOrNil = [self nibNameRotated:[[UIApplication sharedApplication] statusBarOrientation]];
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    return self;
}

- (NSString*) nibNameRotated:(UIInterfaceOrientation)orientation
{
    if( UIInterfaceOrientationIsLandscape(orientation))     return [NSString stringWithFormat:@"%@-landscape", NSStringFromClass([self class])];
    return [NSString stringWithFormat:@"%@", NSStringFromClass([self class])];
}

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    NSString *nibname = [self nibNameRotated:toInterfaceOrientation];
    [[NSBundle mainBundle] loadNibNamed:nibname owner:self options:nil];
    [self viewDidLoad];
}
5
amergin

私はTechZenの受け入れられた答えが好きですが、Adamのコメントで指摘されているように、横向きに回転すると、縦向きのビューコントローラがナビゲーションスタックに残ります。つまり、横長の状態でナビゲーションバーの[戻る]ボタンをタップすると、ユーザーは縦長のビューに移動します。同僚と私は、ナビゲーションスタックから余分なアイテムを手動で削除するアプローチを試みています。動作するようですが、まだ経験が浅いので、何も約束しません。これがサンプルコードです:

ポートレートからランドスケープに移動するには:

[[self navigationController] pushViewController:landscapeViewController animated:NO];
[self removeFromNavigationStack:[MyPortraitViewController class]];

ポートレートに戻るには:

[[self navigationController] pushViewController:portraitViewController animated:NO];
[self removeFromNavigationStack:[MyLandscapeViewController class]];

Animated:NOを使用しない場合、ナビゲーションの状態に関する警告が表示される場合があります。

ヘルパー:

- (void)removeFromNavigationStack:(Class)oldClass {
      UINavigationController *nav = [self navigationController];
      NSMutableArray *newStack = [NSMutableArray array];
      for (UIViewController *vc in nav.viewControllers) {
          if (![vc isMemberOfClass:[oldClass class]]) {
              [newStack addObject: vc];            
          }
      [nav setViewControllers:newStack animated:NO];
  }
1
Deanna Gelbart

もう1つの選択肢 TO Multi Layout View Controller

1
ohho