24

私は他のすべてのためにそしてYESのために戻るUIViewControllerを持っています。スタックの一番上にあるそのビューで、私は新しいをプッシュするために使用します。新しいコントローラーは、内のすべてに対して戻ります。shouldAutorotateToInterfaceOrientation:UIDeviceOrientationPortraitNOpushViewController:animated:UIViewControllerYESshouldAutorotateToInterfaceOrientation:

最初のビューは回転を拒否します(予想どおり)。2番目のビューが押されると、ユーザーはデバイスを回転させることができ、UIが回転します(これも期待どおりです)。2番目のビューが横向きモードで、ユーザーが戻るボタン(を呼び出すpopViewControllerAnimated:)を押すと、最初のビューは回転して表示されます(予期しない!)。

ユーザーがデバイスを回転させて縦向きに戻すと、ビューが回転し、以前と同様に縦向きモードのままになります。これは機能しますが、ユーザーが後ろに回転するまでは醜いです。だから私はこのビューをポートレートモードのままにする方法を探しています。

これまでに見つけた唯一の回避策は、を使用すること-[UIDevice setOrientation:]です。これは警告をスローします(orientation読み取り専用)が、実際に定義されているため機能します。これは巨大なハックであり、私は本当の解決策が欲しいです。実際の解決策を探して、GDBをPhotosアプリケーション(MobileSlideshow.app)に接続し、それもを使用していることを発見しました-[UIDevice setOrientation:]。彼らは異なるルールを持っていると思いますが、内部アプリケーションであること。

期待される自動回転動作を実現する正しい方法はありますか?

4

7 に答える 7

6

UIDevicesetOrientationの合法的な代替手段は次のとおりです。

UIWindow* window = UIApplication.sharedApplication.keyWindow;
UIView* view = [window.subviews objectAtIndex:0];
[view removeFromSuperview];
[window addSubview:view];

これにより、現在のビューコントローラがその方向を評価し、shouldAutorotateToInterfaceOrientationを呼び出して、禁止されている方向から切り替えます。

たとえば、次のコードは、すべての方向をサポートしているが、親が横向きのみをサポートしているViewControllerで使用されます。

- (void)popBack
{
    [self.navigationController popToRootViewControllerAnimated:YES]; 
}

- (IBAction)backPressed:(id)sender
{   
    portraitOrientationPermitted = NO;

    // Force the framework to re-evaluate the interface orientation.
    UIWindow* window = UIApplication.sharedApplication.keyWindow;
    UIView* view = [window.subviews objectAtIndex:0];
    [view removeFromSuperview];
    [window addSubview:view];

    [self performSelector:@selector(popBack) withObject:nil afterDelay:0.8];

    portraitOrientationPermitted = YES;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return portraitOrientationPermitted || 
        UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
于 2011-11-14T20:15:26.160 に答える
5

古い投稿ですが、まだ解決されていません。頭痛の種になっているかもしれない他の人のために、私の解決策を共有したいと思います。

目的:スタック内の1つのビューコントローラーを縦向きと横向きの両方に回転できることを除いて、UINavigationControllerとスタック内のほとんどのビューコントローラーを縦向きに固定します。

問題:topViewControllerがrotableViewControllerであるかどうかを確認することにより、直感的に選択的なshouldAutorotateToInterfaceOrientationを設定しました。ただし、ランドスケープモードでrotableViewControllerからポップバックした後、ナビゲーションコントローラーはランドスケープモードで表示されるようになりましたが、許可されていません。

解決策:キラーは、viewWillAppearアニメーションなしでmodalViewControllerでの回転を禁止し、現在および非表示にすることです。

  1. appViewControllerは、ホストviewControllerとしてウィンドウに追加されます。つまり、RootViewControllerよりもrooterです。
  2. デリゲートがappViewControllerに設定された状態で、navigationControllerがappViewControllerに追加されます。
  3. AppViewControllerで


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if (interfaceOrientation == UIInterfaceOrientationPortrait) return YES;
    return canRotate;
}


- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    [viewController viewDidAppear:animated];
    canRotate = ([navigationController.topViewController isKindOfClass:[MyRotatable class]]);
}


- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    [viewController viewWillAppear:animated];
    if (![navigationController.topViewController isKindOfClass:[MyRotatable class]]) {
        canRotate = NO;
        UIViewController * blanck = [[UIViewController alloc] initWithNibName:nil bundle:nil];
        [self presentModalViewController:blanck animated:NO];
        [self dismissModalViewControllerAnimated:NO];
        [blanck release];
    }
}
于 2011-03-18T01:22:36.500 に答える
4

iOS5は+[UIViewControllerattemptRotationToDeviceOrientation]を追加します。これは私にとって問題を解決します。

于 2012-09-20T22:17:23.337 に答える
1

たぶん仕方がないと言っていたのですが、考えました。正しく理解するのは難しいでしょうがUINavigationController、ルートビューを制御して回転を禁止するものと、それを許可する子ビュー用の2つの別々のを使用すると、機能させることができる場合があります。ルートコントローラーと子コントローラーとの間の遷移を手動で処理します。

正しい戻るボタンを使用するには、子ナビゲーションコントローラーにパッチを適用する必要があります。そしてもちろん、あなたは自分で戻るボタンを押すことを処理しなければならないでしょう。UINavigationBarトランジションが正しく表示されるように、あるナビゲーションコントローラから次のナビゲーションコントローラへのアニメーションを実行するには、おそらくダミーを使用する必要があります。また、ナビゲーションコントローラ間の「プッシュ」遷移もアニメーション化する必要があります。これは、正しく表示されるように少し調整する必要がある場合があります。あなたがしなければならないでしょう:

  1. 発信ナビゲーションコントローラーと完全に一致するようにダミーのナビゲーションバーを構成し、ナビゲーションコントローラーのバーの真上に配置します。(現在のView Controllerの構成をコピーしてUINavigationItem、プッシュすることができます)
  2. 新しいナビゲーションコントローラーを画面外の右端に配置します
  3. 新旧のコントローラーのフレームの右から左への動きをアニメートします
  4. 着信ViewControllerのコピーを作成UINavigationItemし、ダミーのナビゲーションバーにプッシュします
  5. アニメーションが完了したら、ビューからダミーを削除しUINavigationBar、発信ナビゲーションコントローラーも削除します。

これはすべて大変な作業ですが、非常に賢い(そして非常に粘り強い)場合は、それを機能させることができるかもしれません。結果が見たいです!

そうは言っても、setOrientation:AppStoreの承認プロセスを使用してチャンスをつかむほうがよいかもしれません;-)

于 2009-06-09T15:38:09.903 に答える
1

3.0 OSでもう一度試してください(これで話せるようになりました)。これの2つの特別なケースが3.0の下で解決されました:

  1. 横向きのビューの上に縦向きのモーダルビューを表示し、その逆も同様です。例として、添付ファイルを表示するためのMailの3.0より前の動作があります。PDFの場合は横向きに回転し、添付ファイルビューを閉じたときにメッセージの縦向きのビューに戻ることができます。(3.0で横向きのメッセージビューが表示されるようになったため、この動作はなくなったようです)。

  2. ビュースタック内で向きを混合し、スタックをポップしたときに正しい向きを取り戻します。例として、映画のテーブルビューとYouTubeアプリの映画ビューの間の移行があります。

すべての順列のデフォルトの遷移がどのように見えるかについて、いくつかの厄介な美的問題があったようです。スローモーションで見ると奇妙な要素がいくつかありますが、それはあなた自身のコードで後ろ向きに曲がるよりも優れています。

于 2009-06-17T18:52:22.993 に答える
1

この問題の回避策を見つけました。手がかりは、のすべてのビューのすべての方向をサポートすることです。UINavigationController

コントローラに2つのビューがあります。ルートビューは、のみをサポートLandscapeRightし、2番目はとの両方LandscapeRightをサポートしPortraitます。

2番目のビューshouldAutorotateToInterfaceOrientationメソッドは通常どおりに見えます。

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationLandscapeRight) ||
           (interfaceOrientation == UIInterfaceOrientationPortrait);
}

回避策自体はルートビューソースに含まれています。ルートビューはコードの観点から回転しますが、ユーザーはそれを見ることができません。

//auxiliary function
-(void) fixOrientation:(UIInterfaceOrientation)orientation
{
    if (orientation == UIInterfaceOrientationPortrait)
        self.view.transform = CGAffineTransformMakeRotation(M_PI_2);
    else if (orientation == UIInterfaceOrientationLandscapeRight)
        self.view.transform = CGAffineTransformMakeRotation(0);
}

-(void) viewWillAppear:(BOOL)animated
{
    [self fixOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    [self fixOrientation:interfaceOrientation];
    //notice, that both orientations are accepted
    return (interfaceOrientation == UIInterfaceOrientationLandscapeRight) ||
           (interfaceOrientation == UIInterfaceOrientationPortrait);
}

//these two functions helps to avoid blinking
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [UIView setAnimationsEnabled:NO]; // disable animations temporarily

}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    [UIView setAnimationsEnabled:YES]; // rotation finished, re-enable them
}
于 2012-08-08T06:57:49.307 に答える
0

したがって、この厄介なバグは、iOS1からiOS4まで非常に長い道のりを歩んでいます。

私たちが持っている最善の解決策は、このバグを複製し、本当に修正したいことをAppleに知らせていると思います。バグID8478525で再度報告しました。

于 2010-09-25T17:01:57.823 に答える