6

更新: 最初にこの質問に対する私の回答を参照してください。これはバグのようです。最小限のテスト ケースが作成され、レポートが Apple に提出されました。(iPhone OS 3.1 で修正されました。)

これは「I'm so close!」の謎解きです。デパートメント。

Tab Bar ベースの iPhone アプリがあります。各タブには、通常の容疑者 (ナビゲーション バー、テーブル ビューなど) を含むUINavigationControllerがあり、別の VC につながる可能性があります。

現在、これらの下位レベルの VC の 1 つが、ポートレートモードランドスケープ モードで使用されます。しかし、問題があります。ランドスケープに適した VC のshouldAutorotateToInterfaceOrientation:は、そのままでは呼び出されません。何をすべきか?

これが私たちの仕事です。独自のファイルに実装したタブバーコントローラーには、次のものがあります。

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
     return [self.selectedViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}

これにより、ランドスケープに適した VC にリクエストが伝達され、VC もこのメッセージに応答します。私の他のすべての VC はこの方法を実装していないため、デフォルトの縦向きのままです。

問題が解決しました!!!わーい!

まあ、そうではありません。:(

タブ バー コントローラーのMoreNavigationControllerの奥からランドスケープ フレンドリーな VC が呼び出されると、うまくいかないようです。

最初の 4 つのタブ バーUINavigationControllersのいずれかから呼び出された VC と、 MoreNavigationController内から呼び出された同じ VCを比較/対照することにしました。これは少し超詳細になるので、我慢してください。うまくいけば、プレイバイプレイが物事を解明するのに役立つことが証明されます.

アプリが読み込まれると、タブ バー コントローラーの shouldAutorotate... メソッドへの最初の呼び出しがいくつかあります。これらの初期のケースでは、selectedViewControllerは nil です。しかし、最終的に読み込みを終了し、最初のタブ項目が選択され、すべてが順調です。

右。まず、最初の 4 つのタブ バー項目の 1 つを選択し、VC にドリルダウンします。

3 番目のナビゲーション バー項目を選択します。これが 3 番目のナビゲーション コントローラーです。ローテーションをサポートする VC にドリルダウンします。簡単に調べると、親が確かにタブ バーのビュー コントローラー リストの 3 番目のナビゲーション コントローラーであることが確認されます。良い!

デバイスを回転させてみましょう。タブ バー コントローラーは自動回転するように求められます (上記のコードを参照)。selectedViewController3 番目のナビゲーション コントローラーでもあり、さらにナビゲーション コントローラーの上部と可視のビュー コントローラーの両方が、回転をサポートする信頼できる VC に設定されていることがわかります。

したがって、タブ バー コントローラーはshouldAutorotateメッセージを 3 番目のナビゲーション コントローラーに転送しますが、回転に適した VC が最終的にメッセージを受け取ります。(ここでは特別なことはしていません。目的の VC がメッセージを受け取るのは、それが一番上または可視の VC であるためでしょうか?) いずれにせよ、横向きに回転し、サイズが変更され、すべてがうまくいきます。"大成功!"

戻るボタンを押して VC スタックをポップし、ランドスケープ モードを途中で終了します。タブ バー コントローラーが再度照会されます。

ここで少し脇に置いておきます。ナビゲーション コントローラーのtopViewControllerは依然として回転に適した VC ですが、visibleViewControllerはUISnapshotModalViewControllerに設定されています。へー。これは前に見たことがありません...しかし、エリカ・サドゥンは持っています。「消えるビューコントローラー」用のようです(この場合は確かに真実です-大丈夫です)。

ステップを進めていくと、目に見える VC はスナップショットのままですが、特別な VC が最終的になくなるため、最上位の VC は最終的にスタック上の次の VC に変更されます。けっこうだ。

これ、すべてがうまく機能するシナリオです。

今度は、同じテストを試してみましょう。今回は、MoreNavigationController ([その他] タブ バーの項目) に移動し、前と同じ VC クラスにドリルダウンします。私の場合、たまたまタブ バー コントローラーの VC リストの 7 番目です。

ローテーション対応の VC に入ると、今度は直接ローテーションするように求められます。Tab Bar Controller は、回転の許可をまったく求められません。うーん。

親 VC を簡単に確認すると、それがMoreNavigationControllerであることがわかります。わかりました、それは理にかなっています。

それでは、デバイスを回転させてみましょう。何も呼び出されません。ブレークポイントにはヒットしません。私たちのVCにはありません。タブバーコントローラーにはありません。(は?!?!)

ああああああ。スタックをポップして、同じ VC に戻り、再度ローテーションを試みます。変。ここで、Tab Bar Controller で、自動回転の許可を求める呼び出しを受けます。ここで、選択された Controller は信頼できる Nav コントローラー (#7) ですが、今回はそのvisibleViewControllertopViewControllerNILに設定されています。

ここから続行すると、デバッガー コンソールに謎のメッセージが表示されます。

二段回転アニメーションを使用。よりスムーズなシングル ステージ アニメーションを使用するには、このアプリケーションで 2 ステージ メソッドの実装を削除する必要があります。

二段回転アニメーションを使ってないから不思議!ソース コードのどこにもSecondHalfメソッドのバリアントはありません。

悲しいかな、私の回転認識 VC は、回転が発生していることを通知されません (回転が画面上で発生したとしても)。騒乱と悲しみが続く。:(

この時点では、スタックをポップする必要さえありません。

View Controller doc が考えられる問題を示唆していると思います:

向きの変更中にカスタム アニメーションを実行する場合は、2 つの方法のいずれかで実行できます。向きの変更は、回転の開始点、中間点、および終了点で通知が発生する 2 つのステップで発生していました。ただし、iPhone OS 3.0 では、方向の変更を 1 ステップで実行するためのサポートが追加されました。1 ステップの方向変更を使用すると、古い 2 ステップのプロセスよりも高速になる傾向があり、通常、新しいコードには推奨されます。

MoreNavigationControllerはまだ 2 段階のプロセスに応答しているので、1 段階のプロセスを使用しようとする試みがうまくいかないのだろうか? 2 段階のメッセージに応答すると、1 段階のバリアントは機能しないことに注意してください (ドキュメントによると)。私は彼らに返信していませんが、IS の背後に何かがあるのではないかと密かに疑っています。

実際、シングルステップ メソッドをコメント アウトして、willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:に応答しよとすると、メモが表示されます。しかし、それはまだ (ビジュアルの点で) きれいにスタックから飛び出すわけではありません。さらに奇妙な: shouldAutorotateToInterfaceOrientation:で (FirstHalf メッセージを使用して) 自分自身への呼び出しをこっそり実行しようとした場合でも、 willAnimateFirstHalfOfRotationFromInterfaceOrientation:duration: は呼び出されませ。まるで私がそれを定義したことがないかのように、トレース中にすぐに戻ります。はぁ。

それが実況です。

要約すると、Tab Bar Controller のMoreNavigationController内から呼び出された VC のワンステップ デバイス ローテーションを正常に処理した人はいますか? 探究心が知りたい!

4

3 に答える 3

7

Apple は UITabBarController をサブクラス化しないようにアドバイスしているため、代わりにカテゴリを使用して自動回転を処理する簡単な方法を見つけました。More... ビュー コントローラのバグは修正されませんが、Apple に適した方法で作業を完了できると思います (つまり、サブクラス化が少なくて済みます)。

アプリケーションのすべてのタブを適切に自動回転させるために、カスタム ビュー コントローラーで -shouldAutorotateToInterfaceOrientation: を定義しましたが、それらはすべて UITabBarController 内の UINavigationControllers 内にあるため、これら 2 つまでチェーンを介して VC にメッセージが送信されません。も応じます。そこで、アプリのデリゲート ファイルに次の行を追加しました。

MyAppDelegate.h の下部に追加

@interface UITabBarController (MyApp)
@end

@interface UINavigationController (MyApp)
@end

MyAppDelegate.m の下部に追加

@implementation UITabBarController (MyApp) 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return YES;
}
@end

@implementation UINavigationController (MyApp) 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return YES;
}
@end
于 2010-02-05T01:44:44.867 に答える
3

バグがあるようです。再現可能な最小限のテスト ケースを作成し、Apple Bug Reporter ( RADAR Problem 7139857 ) で報告しました。

更新: これは iPhone OS 3.1 で修正されました。

本質的な問題は次のとおりです。

Tab Bar Controller の「More Navigation Controller」が使用されている場合、すでに Navigation Controller スタックにある View Controller は willAnimateRotationToInterfaceOrientation:duration:メッセージを受信しません。

この問題は、タブ バー アイテムのビュー コントローラーが基本的なビュー コントローラーである場合には発生しません。それらがナビゲーション コントローラーであり、"More" ナビゲーション階層が使用されている場合のみ。

コンソール メッセージ (2 段階回転アニメーションに関する) は、フレームワーク内の何か (More Navigation Controller?) がまだ 2 段階アニメーションを使用していることを示唆していますが、iPhone OS 3.0 では単一段階が推奨されています。

その特定のケースでwillAnimateRotationToInterfaceOrientation:が呼び出されない理由を説明できます。Apple のビュー コントローラーのドキュメントによると、このメッセージは、2 段階の前半/後半の方向メッセージが代わりに応答されている場合には呼び出されません。

于 2009-08-13T13:23:36.267 に答える
0

すべての単一のView Controllerが回転を許可するかどうかを決定できるようにする、 Victorbの回答のわずかに変更されたバージョン。

ここでは、コピーとフォークを簡単にするための要点として

AppDelegate.h

@interface UITabBarController (MyApp)
@end

@interface UINavigationController (MyApp)
@end

AppDelegate.m

@implementation UITabBarController (MyApp) 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    UIViewController *selectedVC = [self selectedViewController];
    if ([selectedVC respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) {
        return [selectedVC shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
    }

    //optimistic return - if you want no rotation, you have to specifically tell me!
    return YES;
}
@end

@implementation UINavigationController (MyApp) 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    UIViewController *visibleVC = [self visibleViewController];
    if ([visibleVC respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) {
        return [visibleVC shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
    }

    //optimistic return - if you want no rotation, you have to specifically tell me!
    return YES;
}
@end
于 2012-06-26T04:12:08.943 に答える