web-dev-qa-db-ja.com

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

特定のビューでデバイスの回転をサポートしたいアプリがありますが、他のビューはランドスケープモードでは特に意味をなさないため、ビューをスワップアウトするときに、回転を強制的にポートレートに設定します。

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

[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];

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

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

View 1で横向きと縦向きをサポートし、View 2で縦向きのみをサポートするアプリを作成したい携帯電話を回転させてポートレートに戻します。

94
Dave Verwer

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

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

6
John K

これは事実からかなり後のことですが、Navigation Controllerを使用していない人や、文書化されていないメソッドを使用したくない人が来た場合に備えて:

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

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

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

101
Josh

私が言えることから、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];

次に、ポートレートモードコントローラーで、逆の操作を実行できます。現在横向きになっているかどうかを確認し、横向きになっている場合は、縦向きに戻します。

16
Bdebeez

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

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];
}
16
Michael Gaylord

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

7
Rafael Nobre

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

//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);
}
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;
}

基本的に、空のView Controllerを作成し、スタックにプッシュし、すぐにポップオフすることにより、インターフェイスをポートレート位置に戻すことができます。コントローラーがポップされたら、最初にプッシュしたいコントローラーをプッシュします。視覚的には見栄えがよく、空の任意のView Controllerがユーザーに表示されることはありません。

7
Andrew Vilcsak

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

ただし、「向きが変更されました。UIを更新してください」通知を投稿することをお勧めします。 View Controllerがこの通知を受け取ると、shouldAutorotateToInterfaceOrientation:を呼び出し、目的の向きにYESを返すことで任意の向きを設定できます。

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

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

お役に立てば幸いです。

5

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が現在のデバイスの向きをサポートしているかどうかに応じて、ルートビューを回転させます。最後に、標準のiOS機能を模倣するために、rotateInterfaceToOrientationを実際のデバイスの向きの変更に接続します。このルートコントローラーを同じルートビューコントローラーに追加します。

-(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またはinitloadview通知に登録します:

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

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

私の目的は、風景の向きの変更のみに対処することでした。

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 ];
}
2
user324168

特定のビューでデバイスの回転をサポートしたいアプリがありますが、他のビューは横向きモードでは特に意味をなさないため、ビューをスワップアウトするときに、回転を強制的にポートレートに設定したいと思います。

このスレッドの上記の元の投稿は現在非常に古いことを認識していますが、それに似た問題がありました-つまり。私のアプリのすべての画面は、ユーザーが横向きと縦向きの間で回転できる1つの画面を除いて、縦向きのみです。

これは簡単なことでしたが、他の投稿と同様に、前の画面に戻るときに、現在のデバイスの向きに関係なく、アプリが自動的に縦長に戻るようにしたかったのです。

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

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

これには、ランドスケープモードでより多くの画面スペースが利用できるという点で、アプリにとっても利点があります。これは、問題の画面を使用してPDFファイルを表示するために役立ちます。

お役に立てれば。

1
stephencampbell

iOS 6ソリューション:

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

正確なコードはアプリごとに、そしてあなたがそれを置く場所にも依存します(私はAppDelegateで使用しました)。置換[[self window] rootViewController]使用するもの。私はUITabBarControllerを使用していました。

1
Bo A

結局、これは非常に簡単に解決しました。上記のすべての提案を試みたが、まだ足りなかったので、これが私の解決策でした:

ランドスケープ(左または右)のままにする必要がある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
mrdavenz

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

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

0
Vinzius