web-dev-qa-db-ja.com

一部のビューで自動回転を単一の方向に制限し、他のビューではすべての方向を許可するにはどうすればよいですか?

この質問は、iOSデバイスの回転とUINavigationControllerの複数の制御されたビューに関するものです。一部のビューは縦向きに制限する必要があり、一部のビューは自由に自動回転する必要があります 。 3つのビューを使用して最も単純なセットアップを作成しようとすると、自動回転の動作にいくつかの非常に厄介な癖があることに気付くでしょう。ただし、シナリオは非常に単純なので、自動ローテーションの実装が正しく行われていないか、何かを忘れていると思います。

私は奇妙さを示す非常に基本的なデモアプリを持っていて、それが実際に動作していることを示すビデオを作成しました。

セットアップは非常に基本的です。FirstViewControllerSecondViewController、およびThirdViewControllerと呼ばれる3つのビューコントローラーはすべてAbstractViewControllerを拡張し、クラスの名前とそのラベルを表示します。デバイスが縦向きの場合、shouldAutorotateToInterfaceOrientation:に対してYESを返します。 SecondViewControllerは、このメソッドをオーバーライドして、すべての回転を許可します。 3つの具象クラスはすべて、いくつかの色付きの正方形を追加して、コントローラーをUINavigationControllerに押したり外したりしてビュー間を移動できるようにします。これまでのところ、非常に単純なシナリオだと思います。

デバイスを縦向きまたは横向きに持っている場合、これは私が達成したいだけでなく、期待する結果です。最初の画像では、すべてのビューが「直立」していることがわかります。2番目の画像では、2番目のビューコントローラーのみがデバイスの向きを逆回転させていることがわかります。明確にするために、横向きモードの2番目のビューから3番目のビューに移動できるはずですが、その3番目は縦向きのみをサポートしているため、縦向きでのみ表示する必要があります。結果に問題がないかどうかを確認する最も簡単な方法は、キャリアバーの位置を確認することです。

Expected view orientation for the device in portrait modeExpected view orientation for the device in landscape mode

しかし、実際の結果は完全に異なるため、この質問はここにあります。デバイスを回転させたときのビューと、次に移動するビューに応じて、ビューは回転しません(具体的には、didOrientFromInterfaceOrientation:メソッドが呼び出されることはありません)。 2番目の風景にいて、3番目に移動すると、2番目と同じ向きになります(=悪い)。ただし、2番目から最初に戻ると、画面が「強制」ポートレートモードに回転し、持ち方に関係なく、キャリアバーがデバイスの物理的な上部に表示されます。ビデオはこれをより詳細に示しています。

Actual view orientation for the device in landscape mode

私の質問は2つあります:

  1. 最初のViewControllerが回転して戻るのに、3番目は回転しないのはなぜですか?
  2. 一部のビューのみを自動回転させ、他のビューは自動回転させたくない場合に、ビューから正しい動作を取得するには何をする必要がありますか?

乾杯、EP。

編集:賞金をかける前の最後の手段として、私はこの質問を完全に書き直して、より短く、より明確に、そしてうまくいけばより魅力的に答えを出すようにしました。

30
epologee

簡単に言うと、UINavigationControllerを使用しているため、希望どおりに機能しません。 Appleのドキュメントから:

UIViewControllerがデバイスと一緒に回転しないのはなぜですか?

UITabBarControllerまたはUINavigationControllerのすべての子ViewControllerは、共通の方向セットに同意しません。

すべての子ViewControllerが正しく回転することを確認するには、各タブまたはナビゲーションレベルを表す各ViewControllerにshouldAutorotateToInterfaceOrientationを実装する必要があります。その回転が発生するためには、それぞれが同じ方向に同意する必要があります。つまり、それらはすべて、同じ方向位置に対してYESを返す必要があります。

ここで回転の問題を表示 について詳しく読むことができます。

やりたいことのために、独自のビュー/コントローラースタック管理をロールする必要があります。

8
A. R. Younce

Appデリゲートでブール値を作成して、必要な方向を制御します。たとえば、ブール値を作成してPortraitを有効にし、ViewControllerでPortraitが共有アプリケーションで有効にすることを許可します。

ビューコントローラで、必要な方向を有効または無効にします。

((APPNAMEAppDelegate *)[[UIApplication sharedApplication] delegate]).enablePortrait= NO;

appDelegateで。

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    NSLog(@"Interface orientations");
    if(!enablePortrait)
        return UIInterfaceOrientationMaskLandscape;
    return UIInterfaceOrientationMaskLandscape|UIInterfaceOrientationMaskPortrait;
}

これらのメソッドは、デバイスを回転させるたびに起動されます。これらのBOOLに基づいて、必要な方向を有効にします。

5
Abo3atef

数年前に同様の質問があり、多くの回答がありました。その質問に対する誰かからの最近の回答は次のとおりです。
iPhoneの向きを設定するための文書化された方法はありますか?

私が理解していることから、これは多くの人が抱えている問題であり、ほとんどの場合、ハックがそれを修正する唯一の方法です。これまでに見たことがない場合は、そのスレッドを調べて、何かがうまくいくかどうかを確認してください。

ちなみに、shouldAutorotateで何かを呼び出していたときに同様の問題が発生し、それを修正するためにviewWillAppearにコードを追加しました。正直なところ、それが機能したかどうかは思い出せず、試してみるMacもありませんが、コードを見つけたので、インスピレーションが得られるようにここに貼り付けます。

- (void)viewWillAppear:(BOOL)animated{
  UIInterfaceOrientation o;
  switch ([UIDevice currentDevice].orientation) {
    case UIDeviceOrientationPortrait:
        o = UIInterfaceOrientationPortrait;
        break;
    case UIDeviceOrientationLandscapeLeft:
        o = UIInterfaceOrientationLandscapeLeft;
        break;
    case UIDeviceOrientationLandscapeRight:
        o = UIInterfaceOrientationLandscapeRight;
        break;
    default:
        break;
  }

  [self shouldAutorotateToInterfaceOrientation:o];
}
4
B_.

IOS 6では、これは非常に単純な問題になっています。自動回転するビュー用の特別なクラスを作成するだけです。次に、rootVCにこれを追加します。

-(BOOL)shouldAutorotate{
       BOOL should = NO;

       NSLog(@"%@", [self.viewControllers[self.viewControllers.count-1] class]);
       if ([self.viewControllers[self.viewControllers.count-1] isKindOfClass:[YourAutorotatingClass class]]) {
             should = YES;
       }


       return should;
}

これは古い質問だと思いますが、言及する価値があると思いました。

2
AMayes

このハックは使用しないでください、Appleは「プライベートAPI」の使用に基づいてアプリを拒否します

参考までに、ここに答えを残しておきますが、プライベートAPIの使用はレビューボードをすり抜けることはありません。私は今日何かを学びました:D @ younceがApple docsを正しく引用したように、私が望むことはUINavigationControllerでは達成できません。

私には2つの選択肢がありました。最初に、私はそれをしている間に遭遇したであろうすべての恐怖で、私自身のナビゲーションコントローラーの代用品を書くことができたでしょう。次に、setOrientation:animated:と呼ばれるUIDeviceの文書化されていない機能を使用して、回転をビューコントローラーにハッキングすることができました。

2つ目は魅力的に簡単だったので、私はそれを選びました。これが私がしたことです。セッターが存在しないことに関するコンパイラーの警告を抑制するためのカテゴリーが必要です。

@interface UIDevice (UndocumentedFeatures) 
-(void)setOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated;
-(void)setOrientation:(UIInterfaceOrientation)orientation;
@end

次に、viewWillAppear:でサポートされている方向を確認する必要があります。ここで使用されているUIDeviceメソッドの横に、モーダルビューコントローラーを表示して縦向きを強制することもできますが、これはアニメーション化されずに即座に行われるため、これが私の推奨される方法です。

-(void)viewWillAppear:(BOOL)animated {
    UIDevice *device = [UIDevice currentDevice];
    UIDeviceOrientation realOrientation = device.orientation;

    if ([self shouldAutorotateToInterfaceOrientation:realOrientation]) {
        if (realOrientation != [UIApplication sharedApplication].statusBarOrientation) {

            // Resetting the orientation will trigger the application to rotate
            if ([device respondsToSelector:@selector(setOrientation:animated:)]) {
                [device setOrientation:realOrientation animated:animated];
            } else {
                // Yes if Apple changes the implementation of this undocumented setter,
                // we're back to square one.
            }
        }
    } else if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait]) {
        if ([device respondsToSelector:@selector(setOrientation:animated:)]) {

            // Then set the desired orientation
            [device setOrientation:UIDeviceOrientationPortrait animated:animated];

            // And set the real orientation back, we don't want to truly mess with the iPhone's balance system.
            // Because the view does not rotate on this orientation, it won't influence the app visually.
            [device setOrientation:realOrientation animated:animated];
        }
    }
}

秘訣は、内部デバイスの向きを常にデバイスの「実際の」向きに保つことです。これを変更し始めると、アプリの回転のバランスが崩れます。

しかし、私が今知っているように、これはあなたのアプリを拒否させる確実な方法です。したがって、オプション番号2は悪いオプションです。そのNavigationControllerを書き直すか、すべてのビューで同じ方向セットをサポートするようにします。

乾杯、EP。

2
epologee