iPhoneの向きを設定するための文書化された方法はありますか?


94

特定のビューでデバイスの回転をサポートしたいアプリがありますが、他のビューでは横向きモードでは特に意味がないため、ビューを交換して強制的に回転を縦向きに設定します。

トリックを実行するUIDeviceには、ドキュメント化されていないプロパティセッターがありますが、明らかにコンパイラ警告を生成し、SDKの将来のリビジョンで消える可能性があります。

[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];

オリエンテーションを強制する文書化された方法はありますか?

更新: shouldAutorotateToInterfaceOrientationを既に実装しているため、shouldAutorotateToInterfaceOrientationを探していないので、例を提供すると思いました。

アプリがビュー1では横向きと縦向きをサポートし、ビュー2では縦向きのみをサポートしたいのですが、すべてのビューにshouldAutorotateToInterfaceOrientationを既に実装していますが、ユーザーがビュー1で横向きモードになっていてビュー2に切り替えた場合は、スマートフォンを回転させて縦向きに戻します。


11
私はこれについてバグを提出しました。Appleが上記のAPIを公開するか、または電話が回転するときだけでなく、ビューが最初にロードされたときに、shouldRotateメソッドから返されるYES、NOを尊重することを提案します。
rustyshelf 2008年

2
私はsetOrientationを公開するように要求するバグを提出しました
Jessedc 2010

1
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait]; このメソッドは廃止されており、もう存在しません。
Hikmat Khan、

回答:


6

これは、後のiPhone 3.1.2 SDKでは問題ではなくなりました。スタックに押し戻されているビューの要求された方向を尊重するように見えます。これはおそらく、古いバージョンのiPhone OSを検出し、setOrientationを最新リリースより前の場合にのみ適用する必要があることを意味します。

古いSDKの制限を回避していることがAppleの静的分析で理解されるかどうかは明らかではありません。私は個人的にAppleから次のアップデートでメソッド呼び出しを削除するように言われたので、古いデバイスのハックが承認プロセスを通過するかどうかまだわかりません。


iPhone Simulator 3.3.2はそうではありません。それはまだ機能していません。
アヒル

4
@userスタックにビューをプッシュするときに、どのように向きを要求しますか?
progrmr

4
Appleの静的分析を回避できます。私は、performSelectorを使用し、Obj-Cの素晴らしいダイナミズムに依存することにより、ドキュメント化されていないコードを正常に使用しています。
Kenneth Ballenegger、2010

@KennethBalleneggerガイドラインや契約を読んだとき、そのようなものを非表示にするとアプリが削除され、場合によってはアカウントも削除される可能性があることを覚えています。ドキュメントに記載されていないAPIを使用するだけでリスクを冒すことはありません。
IvanVučica11年

101

これは事実のかなり後のことですが、ナビゲーションコントローラを使用していない、および/または文書化されていないメソッドを使用したくない誰かがやって来る場合に備えて:

UIViewController *c = [[UIViewController alloc]init];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
[c release];

バニラビューコントローラーを表示して閉じるだけで十分です。

もちろん、shouldAutorotateToInterfaceOrientationのオーバーライドで方向を確認または拒否する必要があります。しかし、これによりshouldAutorotate ...がシステムによって再度呼び出されます。


1
すばらしい、これはこの投稿の正解としてマークされていませんが、これで問題の半分が解決されました。stackoverflow.com/questions/5030315。モデルビューのトリックで縦向きに「強制」しますが、横向きに強制することも知っていますか?
epologee、2011

5
ははは!これはバカすぎるよ!しかし、それはうまくいきます!-もちろんそうです!:D
hfossli

すごい、長い間これに苦しんでいます。ありがとう!仲間
Rahul Choudhary、2011年

3
これは、iOS5とiOS6の両方で機能するようです。}];
Inferis

1
これはiOS 7とiOS 8で機能するように見えますが、画面がちらつく顕著な黒い画面があります(主にiOS 8)。
levigroker、2014年

16

縦向きから横向きに強制的に回転させたい場合は、ここにコードがあります。ビューの中心を調整する必要があることに注意してください。私はビューを正しい場所に配置していないことに気づきました。それ以外の場合は、完全に機能しました。先端をありがとう。

if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation)){

        [UIView beginAnimations:@"View Flip" context:nil];
        [UIView setAnimationDuration:0.5f];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

        self.view.transform = CGAffineTransformIdentity;
        self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
        self.view.bounds = CGRectMake(0.0f, 0.0f, 480.0f, 320.0f);
        self.view.center = CGPointMake(160.0f, 240.0f);

        [UIView commitAnimations];
}

UIAlertViewを追加した場合も機能しますか?私CGAffineTransformMakeRotationはビューを回転させようとしましたが、ステータスバーの方向、つまり-degreeToRadian(angle)に従ってUIAlertViewはまだですか?あなたはこのようなものを手に入れましたか?
NeverHopeless 2014

これをaで行う最も簡単な方法UIAlertViewは、viewコントローラーをalertViewのデリゲートとして設定し、次に- (void) didPresentAlertView:(UIAlertView *) alertViewで、現在のに基づいてローテーションを実行することです[UIApplication sharedApplication].statusBarOrientation。あなたがそれをアニメーション化しないならば、あまり変に見えるべきではありません。
マイケルゲイロード

16

私の知る限りでは、このsetOrientation:方法は機能しません(またはおそらく機能しなくなります)。これは私がこれを行うためにやっていることです:

まず、この定義をファイルの先頭、#importsのすぐ下に配置します。

#define degreesToRadian(x) (M_PI * (x) / 180.0)

次に、viewWillAppear:メソッドで

[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];     
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {  
    self.view.transform = CGAffineTransformIdentity;
    self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
    self.view.bounds = CGRectMake(0.0, 0.0, 480, 320);
}

これをアニメーション化したい場合は、次のように全体をアニメーションブロックでラップできます。

[UIView beginAnimations:@"View Flip" context:nil];
[UIView setAnimationDuration:1.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];     
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {  
    self.view.transform = CGAffineTransformIdentity;
    self.view.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
    self.view.bounds = CGRectMake(0.0, 0.0, 480, 320);
}
[UIView commitAnimations];

次に、ポートレートモードのコントローラーで、逆の操作を行うことができます。現在のランドスケープになっているかどうかを確認し、そうであれば、回転させてポートレートに戻します。


1
self.viewの代わりに、self.window.viewを回転させる必要があります。これは、ビューの上にUITabBarまたは他のコントローラーがある場合に便利です。
Borut Tomazin、

7

UIViewController画面上、UINavigationController横向きで問題が発生していました。ただし、次のView Controllerがフローでプッシュされると、デバイスを縦向きに戻す必要がありました。

私が気付いたのshouldAutorotateToInterfaceOrientation:は、新しいView Controllerがスタックにプッシュされたときにこのメソッドが呼び出されず、View Controllerがスタックからポップされたときに呼び出されていることです

これを利用して、私のアプリの1つでこのコードスニペットを使用しています。

- (void)selectHostingAtIndex:(int)hostingIndex {

    self.transitioning = YES;

    UIViewController *garbageController = [[[UIViewController alloc] init] autorelease];
    [self.navigationController pushViewController:garbageController animated:NO];
    [self.navigationController popViewControllerAnimated:NO];

    BBHostingController *hostingController = [[BBHostingController alloc] init];
    hostingController.hosting = [self.hostings objectAtIndex:hostingIndex];
    [self.navigationController pushViewController:hostingController animated:YES];
    [hostingController release];

    self.transitioning = NO;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    if (self.transitioning)
        return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
    else
        return YES;
}

基本的に、空のビューコントローラーを作成し、それをスタックにプッシュし、すぐにポップオフすることで、インターフェイスを縦向きの位置に戻すことができます。コントローラーがポップされたら、最初に押すつもりだったコントローラーを押すだけです。見た目はすばらしく、空の任意のビューコントローラはユーザーには表示されません。


こんにちは、VCをプッシュする前に正しい方向にVCを強制するメソッドを実装しましたが、それはポートレートの方向を強制する場合にのみ機能することがわかりました(現在のビューがポートレートで、次のビューを強制的にランドスケープにしたい場合、 shouldAutorotateToInterfaceOrientation:popingのときは呼び出さないでください)ビューを強制的に横向きにする回避策を見つけましたか?
Rafael Nobre、

おもしろい-申し訳ありませんが、この問題は発生していません。私はプッシュとポップのシーケンスをいじってみますが、あなたが何かを思いつく可能性は十分あります。
Andrew Vilcsak 2010

7

プログラムでiPhoneを必要な方向に強制する簡単な方法があります-kdbdallasJoshによってすでに提供されている2つの回答を使用します。

//will rotate status bar
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];


//will re-rotate view according to statusbar
UIViewController *c = [[UIViewController alloc]init];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
[c release];

魅力のように動作します:)

編集:

iOS 6の場合、この関数を追加する必要があります:(モーダルビューコントローラーで動作します)

- (NSUInteger)supportedInterfaceOrientations
{
    return (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight);
}

私にとって、それは魅力のようには機能しません。ナビゲーションバーとツールバーは、横向きビューでの高さに縮小します。最上位のビューを削除して再追加する方法では、正しい高さが維持されますが、欠点もあります。ナビゲーションバーが少し下に移動します(テタリングバーが有効になっている場合と同様)
AlexWien

それは私の側で、モーダルとプッシュされたビューコントローラーの両方で機能します。ただし、iOS 5のみ。:(
Guntis Treulands 2013年

はい、iOS 5でも機能します。ios6では、モーダルランドスケープビューコントローラーを閉じると、ナビゲーションバーの高さが縮小します
AlexWien 2013

7

私はこれに対する良い解決策を探して掘っています。トリックを実行するこのブログ投稿を見つけました:キーから最も外側のビューを削除しUIWindowて再度追加すると、システムはshouldAutorotateToInterfaceOrientation:ビューコントローラーからメソッドを再クエリし、正しい方向が適用されるようにします。それを参照してください:iphoneにuiviewの向きを強制する


このソリューションは私にとって最も効果的でした。重要なのは、空のmodalViewControllerを表示する修正により、ビューコントローラーをスタックにプッシュするアニメーションが不正になることです。このUIWindowメソッドは同じ問題を抱えていません。
Rik Smith-Unna 2012

5

ジョシュの答えは私にはうまくいきます。

ただし、「向きは変更されました。UIを更新してください」という通知投稿することをお勧めします。この通知がView Controllerによって受信されるとshouldAutorotateToInterfaceOrientation:、が呼び出され、必要な向きに戻っYESて任意の向きを設定できます。

[[NSNotificationCenter defaultCenter] postNotificationName:UIDeviceOrientationDidChangeNotification object:nil];

唯一の問題は、これがアニメーションなしで方向転換強制することです。beginAnimations:との間でこの行をラップする必要がありますcommitAnimationsスムーズな移行を実現するには、ます。

お役に立てば幸いです。


3

FWIW、これは手動で方向を設定する私の実装です(アプリのルートビューコントローラーに移動するには、natch):

-(void)rotateInterfaceToOrientation:(UIDeviceOrientation)orientation{

    CGRect bounds = [[ UIScreen mainScreen ] bounds ];
    CGAffineTransform t;
    CGFloat r = 0;
    switch ( orientation ) {
        case UIDeviceOrientationLandscapeRight:
            r = -(M_PI / 2);
            break;
        case UIDeviceOrientationLandscapeLeft:
            r  = M_PI / 2;
            break;
    }
    if( r != 0 ){
        CGSize sz = bounds.size;
        bounds.size.width = sz.height;
        bounds.size.height = sz.width;
    }
    t = CGAffineTransformMakeRotation( r );

    UIApplication *application = [ UIApplication sharedApplication ];

    [ UIView beginAnimations:@"InterfaceOrientation" context: nil ];
    [ UIView setAnimationDuration: [ application statusBarOrientationAnimationDuration ] ];
    self.view.transform = t;
    self.view.bounds = bounds;
    [ UIView commitAnimations ];

    [ application setStatusBarOrientation: orientation animated: YES ];     
}

次のUINavigationControllerDelegateメソッドと組み合わせて(あなたが使用していると仮定してUINavigationController):

-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    // rotate interface, if we need to
    UIDeviceOrientation orientation = [[ UIDevice currentDevice ] orientation ];
    BOOL bViewControllerDoesSupportCurrentOrientation = [ viewController shouldAutorotateToInterfaceOrientation: orientation ];
    if( !bViewControllerDoesSupportCurrentOrientation ){
        [ self rotateInterfaceToOrientation: UIDeviceOrientationPortrait ];
    }
}

これにより、着信UIViewControllerが現在のデバイスの向きをサポートしているかどうかに応じてルートビューが回転します。最後に、rotateInterfaceToOrientation標準のiOS機能を模倣するために、実際のデバイスの向きの変更に接続する必要があります。このイベントハンドラーを同じルートビューコントローラーに追加します。

-(void)onUIDeviceOrientationDidChangeNotification:(NSNotification*)notification{
    UIViewController *tvc = self.rootNavigationController.topViewController;
    UIDeviceOrientation orientation = [[ UIDevice currentDevice ] orientation ];
    // only switch if we need to (seem to get multiple notifications on device)
    if( orientation != [[ UIApplication sharedApplication ] statusBarOrientation ] ){
        if( [ tvc shouldAutorotateToInterfaceOrientation: orientation ] ){
            [ self rotateInterfaceToOrientation: orientation ];
        }
    }
}

最後に、登録のためUIDeviceOrientationDidChangeNotificationにある通知initまたはloadviewそうのように:

[[ NSNotificationCenter defaultCenter ] addObserver: self
                                           selector: @selector(onUIDeviceOrientationDidChangeNotification:)
                                               name: UIDeviceOrientationDidChangeNotification
                                             object: nil ];
[[ UIDevice currentDevice ] beginGeneratingDeviceOrientationNotifications ];

これは、このページの回答のうち、ナビゲーションコントローラーのコードにうまく適応できた唯一の回答です。マイナーな問題の1つは、回転したナビゲーションバーの高さが、通常のメカニズムで回転した場合のように縦向きと横向きの間で変化しないことです。
Dan Dyer

@DanDyerは、ナビゲーションバーの高さが間違っているという問題を解決しましたか?(特にios6では高さが間違っています)
AlexWien 2013

@AlexWien私は結局、これを行うべきではないことをクライアントに納得させることができました。iOS 6の場合、新しいshouldAutorotateメソッドを使用して何かを行う必要がある場合があります(stackoverflow.com/a/12586002/5171を参照)。
Dan Dyer 2013

@DanDyerは昨日それを解決し、ViewDidAppearのナビゲーションとステータスバーの単純な非表示と表示がそれを解決しました。これですべての作業(SDK ios6、ターゲットios5)がターゲットios6で再テストする必要があります
AlexWien

2

これは私のために働きます(ヘンリー・クックありがとう):

私の目的は、横向きの変更のみを処理することでした。

initメソッド:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(orientationChanged:)
                                             name:UIDeviceOrientationDidChangeNotification
                                           object:nil];

- (void)orientationChanged:(NSNotification *)notification {    
    //[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
    UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
    CGRect bounds = [[ UIScreen mainScreen ] bounds ];
    CGAffineTransform t;
    CGFloat r = 0;
    switch ( orientation ) {
        case UIDeviceOrientationLandscapeRight:
            r = 0;
            NSLog(@"Right");
            break;
        case UIDeviceOrientationLandscapeLeft:
            r  = M_PI;
            NSLog(@"Left");
            break;
        default:return;
    }

    t = CGAffineTransformMakeRotation( r );

    UIApplication *application = [ UIApplication sharedApplication ];
    [ UIView beginAnimations:@"InterfaceOrientation" context: nil ];
    [ UIView setAnimationDuration: [ application statusBarOrientationAnimationDuration ] ];
    self.view.transform = t;
    self.view.bounds = bounds;
    [ UIView commitAnimations ];

    [ application setStatusBarOrientation: orientation animated: YES ];
}

1

特定のビューでデバイスの回転をサポートしたいアプリがありますが、他のビューでは横向きモードでは特に意味がないため、ビューを交換して強制的に回転を縦向きに設定します。

このスレッドの上記の元の投稿は非常に古いことに気づきましたが、同様の問題がありました。私のアプリのすべての画面は縦向きのみですが、ユーザーが横向きと縦向きの間で回転できる1つの画面は例外です。

これは単純明快ですが、他の投稿と同様に、前の画面に戻ったときに、現在のデバイスの向きに関係なく、アプリを自動的に縦向きに戻したいと思いました。

私が実装したソリューションは、横長モードのときはナビゲーションバーを非表示にすることでした。つまり、ユーザーは縦長のときにのみ前の画面に戻ることができます。したがって、他のすべての画面は縦向きにすることしかできません。

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)pInterfaceOrientation {
    BOOL lHideNavBar = self.interfaceOrientation == UIInterfaceOrientationPortrait ? NO : YES;
    [self.navigationController setNavigationBarHidden:lHideNavBar animated:YES];
}

これには、横向きモードで利用できる画面スペースが増えるという点で、私のアプリに追加の利点もあります。問題の画面はPDFファイルの表示に使用されるため、これは便利です。

お役に立てれば。


1

結局簡単に解決しました。私は上記のすべての提案を試しましたが、それでも不十分でしたので、これが私の解決策でした:

横向きのままにする必要があるViewController(左または右)では、向きの変更をリッスンします。

    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(didRotate:)
                                             name:UIDeviceOrientationDidChangeNotification object:nil];

次にdidRotateで:

- (void) didRotate:(NSNotification *)notification
{   if (orientationa == UIDeviceOrientationPortrait) 
    {
        if (hasRotated == NO) 
        {
            NSLog(@"Rotating to portait");
            hasRotated = YES;
            [UIView beginAnimations: @"" context:nil];
            [UIView setAnimationDuration: 0];
            self.view.transform = CGAffineTransformIdentity;
            self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-90));
            self.view.bounds = CGRectMake(0.0f, 0.0f, 480.0f, 320.0f);
            self.view.frame = CGRectMake(0.0f, 0.0f, 480.0f, 320.0f);
            [UIView commitAnimations];

    }
}
else if (UIDeviceOrientationIsLandscape( orientationa))
{
    if (hasRotated) 
    {
        NSLog(@"Rotating to lands");
        hasRotated = NO;
        [UIView beginAnimations: @"" context:nil];
        [UIView setAnimationDuration: 0];
        self.view.transform = CGAffineTransformIdentity;
        self.view.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(0));
        self.view.bounds = CGRectMake(0.0f, 0.0f, 320.0f, 480.0f);
        self.view.frame = CGRectMake(0.0f, 0.0f, 320.0f, 480.0f);
        [UIView commitAnimations];

    }
}

view.bounds / frameが明示的にリセットされているため、自動サイズ変更を使用するスーパービュー/サブビューに注意してください...

ビューのランドスケープを維持するためのこのメソッドの唯一の注意点は、変化がないように見えるほうがよい場合に、発生する必要のある方向間の固有のアニメーション切り替えです。


1

iOS 6ソリューション:

[[[self window] rootViewController] presentViewController:[[UIViewController alloc] init] animated:NO completion:^{
    [[[self window] rootViewController] dismissViewControllerAnimated:NO completion:nil];
}];

正確なコードはアプリごとに、またどこに配置するかによって異なります(私はAppDelegateで使用しました)。[[self window] rootViewController]使用するものに置き換えてください。を使用していましたUITabBarController


0

私は解決策を見つけ、フランス語で何かを書きました(ただし、コードは英語です)。ここに

方法は、コントローラーをウィンドウビューに追加することです(コントローラーは、shouldRotate ....関数の適切な実装を所有している必要があります)。


-3

UIViewControllersを使用している場合、このメソッドがあります。

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

NO回転させたくないビューを含むビューコントローラに戻ります。

詳細はこちら


1
これにより回転が停止します。私が探しているのは、ユーザーが横向きの場合、回転を強制的に縦向きに戻すことです。上記の例を追加して、より良い意味を説明しました。
Dave Verwer、2008年

-3

もちろん、実行時にこれを実行することはできないと思いますが、UIに90度の変換を適用することもできます。


私が最初に投稿したコードではそれが可能ですが、それがいつ機能しなくなるかはわかりません;)
Dave Verwer

-3

これは私が使用するものです。(コンパイル警告が表示されますが、シミュレータとiPhoneの両方で機能します)

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];

これは4.1でも機能させるのに十分であることがわかりました。ただし、ステータスバーが非表示に設定されているため、上部に20ピクセルのギャップが生じます:(
Anthony Main

setOrientationはプライベートAPIであり、それを使用するアプリは拒否されます。
alones
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.