iPhone:ランドスケープのみで、最初のaddSubviewの後、UITableViewControllerが正しく回転しません
質問
このための最小限のXcodeプロジェクトは、 github で入手できます。
UIWindowで、2番目(およびそれ以降)のUITableViewをサブビューとして追加すると、それらは適切に回転せず、したがって横向きに表示されます。これは、シミュレータでのみテストされます。ここにあなたのための小さなコードがあります:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
ShellTVC* viewA = [[ShellTVC alloc] initWithTitle:@"View A"];
ShellTVC* viewB = [[ShellTVC alloc] initWithTitle:@"View B"];
// The first subview added will rotate to landscape correctly.
// Any subsequent subview added will not.
// You may try this by various commentings and rearranging of these two statements.
[window addSubview:[viewA tableView]];
[window addSubview:[viewB tableView]];
[window makeKeyAndVisible];
}
viewBは横向きに表示されます。 viewBのaddSubviewをコメントアウトすると、viewAが正しく表示されます。これをviewAに対してのみ行うと、viewBが正しく表示されます。
UIWindowは作成されていますが、NIBを介してこれらのUITableViewControllerを作成していません。
ご参考までに、ShellTVCはUITableViewControllerであり、このメソッドを実装しています:
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
また、plistファイルのUIInterfaceOrientationをUIInterfaceOrientationLandscapeLeftに設定しました。
解決
これを行う方法、おそらく正しい方法を見つけたと思います。
- 「マスター」を作成します; shouldAutorotate ...を実装するUIViewControllerサブクラスを追加し、これをウィンドウ上の唯一のビューとして追加します。
- viewAまたはviewBを切り替えるには、dismissModalViewControllerAnimatedの組み合わせを使用します:& presentModalViewController:animated:このマスタービューコントローラー上。
ここにいくつかのコードがあります:
// this doesn't really do much but implement shouldAutorotate...
@interface MasterViewController : UIViewController
@end
@implementation MasterViewController
- (BOOL) shouldAutorotateToInterfaceOrientation(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
@end
@interface MyAppDelegate : NSObject <UIApplicationDelegate> {
MasterViewController* masterVC;
UIViewController* activeTVC;
UIViewController* onDeckTVC;
}
@end
- (void)applicationDidFinishLaunching:(UIApplication *)application {
UIViewController* masterVC = [[MasterViewController alloc] init];
activeTVC = [[ShellTVC alloc] initWithTitle:@"View A"];
onDeckTVC = [[ShellTVC alloc] initWithTitle:@"View B"];
[window addSubview:masterView.view];
[window makeKeyAndVisible];
[masterVC presentModalViewController:activeTVC animated:NO];
}
// you would call this to toggle between "View A" and "View B"
- (void)toggleTVC {
UITableViewController *hold = activeTVC;
activeTVC = onDeckTVC;
onDeckTVC = hold;
[masterVC dismissModalViewControllerAnimated:NO];
[masterVC presentModalViewController:activeTVC animated:NO];
}
これはなぜ機能するのですか?
-
すべての方向の変更は、ビューではなくView Controllerを経由します。
-
私が知る限り、ウィンドウに追加する最初のビューまたはサブビューは、特別なソースを取得します。そのビューにView Controllerがある場合、ウィンドウに表示されます。
つまり、最初のサブビューについてのみ、次のコードを考えることができます。
[window addSubview:masterVC.view];
このようなことをする(実際の方法ではありません!):
[window addSubview:masterVC.view withViewController:masterVC];
それについてはそれ以上理解できません。私はこれを最初のサブビューで行うことができるが、他のサブビューではできないので、非常に困惑しています。詳細情報を歓迎します。これがあなたを助けたかどうか教えてください。
他のヒント
どうやらviewSの子としてビューを追加すると、正しく回転します。これは私のプロジェクトにとって素晴らしい解決策ではありませんが、唯一の回避策のようです。
残念ながら、サブビューには、方向の変更が発生したときにサポートする方向についてのみ尋ねられます。
したがって、変更されたことがわかっている場合は、スタックに新しいView Controllerをプッシュする前に方向を設定します。
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
はい、これはサポートされていない通話です。
UIApplicationオブジェクトを使用して、特定のデバイスの向きを強制できます。
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
はい、複数のXIBを使用してこの問題を解決する必要があると思います。私は過去に読んだ本の一つを通してこの解決策を見たことを覚えています。そうでない場合は、トランスレーションとビュー内のオブジェクトの位置を試してみてください...独立したXIBを用意した方が良いでしょう。
これは動作するはずです。
- (void)viewDidLoad {
if (([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft) ||
([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight))
{
self.view.frame = CGRectMake(0, 0, 1024, 748);
} else {
self.view.frame = CGRectMake(0, 0, 768, 1004);
}
}