web-dev-qa-db-ja.com

単一のUIViewControllerのみを横方向と縦方向の両方に回転させる方法は?

私のアプリはiphoneデバイス(iphone 4と5の両方)専用であり、ios 6

私のアプリ全体はportraitモードのみをサポートしています。しかし、「ChatView」というビューが1つあり、landscapeモードとportraitモードの両方をサポートしたいと考えています。

必要なデバイスの回転を次のように設定しました-

enter image description here

また、「ChatView」で回転をサポートするために次のコードを試してみました-

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscape;
}

しかし、そのビューを回転させることはできませんでした。

私はこれを多く検索しましたが、私の問題の解決策を見つけることができませんでした。

また、「ChatView」には、ボタン、フレームがプログラムで設定されるテキストフィールドなどのオブジェクトがあります。だから私はまた、ランドスケープモードのためにそれらのすべてのオブジェクトのフレームを設定する必要があるのか​​知りたいですか?

私を助けてください。

ありがとう.....

60
Rohan

ViewControllerの回転を1つだけサポートしたい場合、アプリケーションは.plistファイル。別の方法として、アプリを横向きと縦向きの両方でサポートし、チャットビューを除くすべてのViewControllerの回転を縦向きに固定する方法があります。

[〜#〜] edit [〜#〜]

UINavigationControllerをサブクラス化するには、名前が新しいファイルを作成します。 CustomNavigationControllerおよびUINavigationControllerのサブクラスにします。

。hファイル

#import <UIKit/UIKit.h>

@interface CustomNavigationController : UINavigationController

@end

。mファイル

#import "CustomNavigationController.h"

@interface CustomNavigationController ()

@end


@implementation CustomNavigationController

-(BOOL)shouldAutorotate
{
    return NO;
}

-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}

@end

メインクラスxibのUINavigationControllerのクラスをCustomNavigationControllerとして設定します。 YPUに役立つことを願っています。

28
NightFury

シンプルですが、非常にうまく機能します。 IOS 7.1および8

AppDelegate.h

@property () BOOL restrictRotation;

AppDelegate.m

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if(self.restrictRotation)
    return UIInterfaceOrientationMaskPortrait;
else
    return UIInterfaceOrientationMaskAll;
}

ViewController

-(void) restrictRotation:(BOOL) restriction
{
    AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
    appDelegate.restrictRotation = restriction;
}

viewDidLoad

[self restrictRotation:YES]; or NO
63
Alan10977

View Controllerは、アプリ自体でサポートされていない位置に回転することはありません。可能なすべての回転を有効にしてから、回転するはずのないView Controllerで次の行を配置する必要があります

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

ChatViewでは、次のようになります。

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}

回転後にレイアウトを変更する必要がある場合は、サブビューに適切な変更を実装する必要があります

- (void)viewWillLayoutSubviews

つかいます self.view.boundsは、viewの現在のサイズを確認します。self.view.frameは回転後も変化しません。

21
johnyu

特定のviewcontroller.m回転させたい

このメソッドを追加します。

- (BOOL)canAutoRotate
{
    return YES;
}

その後、AppDelegate.m

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    UIViewController *currentViewController = [self topViewController];

    if ([currentViewController respondsToSelector:@selector(canAutoRotate)]) {
        NSMethodSignature *signature = [currentViewController methodSignatureForSelector:@selector(canAutoRotate)];

        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];

        [invocation setSelector:@selector(canAutoRotate)];
        [invocation setTarget:currentViewController];

        [invocation invoke];

        BOOL canAutorotate = NO;
        [invocation getReturnValue:&canAutorotate];

        if (canAutorotate) {
            return UIInterfaceOrientationMaskAll;
        }
    }

    return UIInterfaceOrientationMaskPortrait;
}

- (UIViewController *)topViewController
{
    return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}

- (UIViewController *)topViewControllerWithRootViewController:(UIViewController *)rootViewController
{
    if ([rootViewController isKindOfClass:[UITabBarController class]]) {
        UITabBarController* tabBarController = (UITabBarController*)rootViewController;
        return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
    } else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController* navigationController = (UINavigationController*)rootViewController;
        return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
    } else if (rootViewController.presentedViewController) {
        UIViewController* presentedViewController = rootViewController.presentedViewController;
        return [self topViewControllerWithRootViewController:presentedViewController];
    } else {
        return rootViewController;
    }
}
16
Ted

テッドの答えは、ノルウェーのアレキサンダーが言及した問題とうまく機能します。しかし、私はアレクサンダーが説明したように問題が起こっていないことを理解しました、

現在横向き(すべての方向が有効)になっているViewController BがViewController Aに戻ると(ユーザーが戻るボタンをクリックした後、supportedInterfaceOrientationsForWindowは呼び出されず、ViewController Aは横向きになります)

実際に、ユーザーが戻るボタンをクリックした後、現在横向きになっているViewController B(すべての方向が有効)がViewController A(縦のみ)に戻るとき、Appdelegate

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;

呼ばれています。ただし、ルートView ControllerはViewController B(回転対応View Controller)ですが、ViewController Bはまだ戻っているため、ViewController Aは縦向きに戻りません。

-(BOOL)shouldAutorotate{

    return YES;
}

戻るボタンを押すと、ViewController Bで「shouldAutorotate-> NO」が返されます。ViewControllerAは縦向きになります。これは私がやったことです

@property (nonatomic, assign) BOOL canAutoRotate;

#pragma mark - Public methods
- (BOOL)canAutoRotate
{
    return _canAutoRotate;
}

#pragma mark - Button actions
- (void)backButtonPressed:(UIButton *)sender {
    _canAutoRotate = NO;
   (...)
}

#pragma mark - Init
- (id)init{
    if(self=[super init]) {
        _canAutoRotate = YES;
    }
    return self;
}
4

Swift 3コーシャバージョン

誰かが問題を抱えている場合のために、これをここに残しました。

Appleのドキュメント for supportedInterfaceOrientationsのコメント:

ユーザーがデバイスの向きを変更すると、システムは、ルートビューコントローラーまたはウィンドウを埋める最上部に表示されるビューコントローラーでこのメソッドを呼び出します。 View Controllerが新しい方向をサポートしている場合、ウィンドウとView Controllerは新しい方向に回転します。このメソッドは、View ControllerのshouldAutorotateメソッドがtrueを返す場合にのみ呼び出されます。

簡単に言うと、ルートビューコントローラーのsupportedInterfaceOrientationsをオーバーライドして、最上位の子ビューコントローラーの値とそれ以外のデフォルト値を返す必要があります。

あなたがすべきことは、アプリがすべてのモードをサポートしているかどうかを確認することです(ターゲットの一般設定またはInfo.plistの展開情報に移動します)、ルートView Controllerのクラスを見つけます。汎用UIViewController、UINavigationController、UITabBarControllerまたはカスタムクラスのいずれかです。次の方法で確認できます。

dump(UIApplication.shared.keyWindow?.rootViewController)

またはあなたが好きな他の方法。

いくつかのCustomNavigationControllerにします。したがって、次のようにsupportedInterfaceOrientationsをオーバーライドする必要があります。

class CustomNavigationController: UINavigationController {

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return topViewController?.supportedInterfaceOrientations ?? .allButUpsideDown
    }
}

インスタンスのポートレート方向のみをサポートするView Controllerでは、次のようにsupportedInterfaceOrientationsをオーバーライドします。

class ChildViewController: UIViewController {

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }
}

次に、ルートView Controllerと最上位にあるView ControllerのshouldAutorotateがすでにtrueを返しているかどうかを確認することを忘れないでください。そうでない場合、これをクラス定義に追加します。

override var shouldAutorotate: Bool {
    return true
}

それ以外の場合、supportedInterfaceOrientationsはまったく呼び出されません。

どうぞ!

1つのView Controllerのみが多数の方向をサポートし、他のView Controllerはサポートしないという反対の問題を修正する必要がある場合は、この変更をすべてのView Controllerに加えてください。

これが役立つことを願っています。

2
Artem Kirillov

この問題の歴史についてはわかりませんが(現在= iOS 10の期間)、これを投稿したときに最も簡単な解決策がありませんでした 2016年10月。

これが欲しいと仮定すると:

  1. iOS 7以降のみのサポート(iOS 10を含む)
  2. すべての方向をサポートするView Controllerもあれば、方向のサブセットをサポートするView Controllerもあります。 つまり、1つのView Controllerはポートレートのみをサポートし、他のすべてのView Controllerはすべての方向をサポートする必要があります
  3. すべてのView Controllerが回転をサポートしている場合、すべてのView Controllerが自動回転する必要があります(つまり、View Controllerでこの問題を修正するコードは必要ありません)
  4. XIB/NIB /ストーリーボードにUINavigationControllersを追加せずに追加することをサポート

...次に(IMO)最も簡単な解決策はINavigationControllerDelegateを作成で、サブクラスUINavigationControllerではありません(上記の前提4に違反します)。

これを解決したとき、私の最初のViewController a UINavigationControllerDelegateにすることにしました。このView Controllerは、それ自体をNavigation Controllerのデリゲートとして設定し、許可されている方向を返します。私の場合、デフォルトではすべての方向が許可され、ポートレートが優先されますが、特定のケースではポートレートのみが許可されます。以下のコードは、Swift 3/XCode 8:

    class iPhoneStartViewController: UIViewController {

        var navInterfaceOrientationMask: UIInterfaceOrientationMask?
        var navInterfaceOrientationPreferred: UIInterfaceOrientation! = .portrait

        override func viewDidLoad() {
            super.viewDidLoad()
            self.navigationController?.delegate = self
        }

        @IBAction func cameraButtonPressed(_ sender: AnyObject) {
            if PermissionsHelper.singleton().photosPermissionGranted() == false {
                self.navInterfaceOrientationMask = nil   // default is: all orientations supported
                self.performSegue(withIdentifier: "segueToPhotoAccess", sender: self)
            } else {
                self.navInterfaceOrientationMask = .portrait // this stops the next view controller from being to rotate away from portrait
                self.performSegue(withIdentifier: "segueToCamera", sender: self)
            }
        }
     }

     // lock orientation to portrait in certain cases only. Default is: all orientations supported
    extension iPhoneStartViewController : UINavigationControllerDelegate {
        public func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask {
            if let mask = self.navInterfaceOrientationMask {
                return mask
            } else {
                return .all
            }
        }

        public func navigationControllerPreferredInterfaceOrientationForPresentation(_ navigationController: UINavigationController) -> UIInterfaceOrientation {
            return self.navInterfaceOrientationPreferred
        }
    }
2
xaphod

uINavigationControllerのサブクラスを次のように作成します。

MyNavigationController.h

#import <UIKit/UIKit.h>

@interface MyNavigationController : UINavigationController

@end

MyNavigationController.m

#import "MyNavigationController.h"
#import "ServicesVC.h"

@implementation MyNavigationController

-(BOOL)shouldAutorotate{

    return YES;
}

-(NSUInteger)supportedInterfaceOrientations{

    if ([[self.viewControllers lastObject] isKindOfClass:[ServicesVC class]]) {
        return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
    }

    return UIInterfaceOrientationMaskAll;
}

@end

ビューコントローラーの名前がServicesVCであると仮定します

1
Jesus

@iAnumの回答に基づいて、自動回転とUIViewControllerクラスの検出を有効にしました。

これは、そうしないと「特別なView Controller」に出入りするのが縦向きに修正されず、サポートされていない向きで立ち往生するためです。

ランドスケープをサポートするビューは1つしかなかったため、カスタムNavigation View Controllerでハードコーディングしました。

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    //Access the current top object.
    UIViewController *viewController = [self.viewControllers lastObject];
    //Is it one of the landscape supported ones?
    if ([viewController isMemberOfClass:[SpecialViewController class]]) {
        return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
    } else
        return UIInterfaceOrientationMaskPortrait;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    //Access the current top object.
    UIViewController *viewController = [self.viewControllers lastObject];
    //Is it one of the landscape supported ones?
    if ([viewController isMemberOfClass:[SpecialViewController class]]) {
        return interfaceOrientation;
    } else
        return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}

ここで説明されているVCのポップに問題があります https://stackoverflow.com/a/15057537/1277350 ここで、横向きで押しても方向メソッドが呼び出されないため、モーダルビューを表示および非表示にすることで、少しハックするようになりました。

そして、willShowViewControllerを起動する場合は、self.delegate = selfを設定し、UINavigationControllerDelegateを以下のコードとともにカスタムナビゲーションコントローラーに追加する必要があることを覚えておいてください。

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationPortrait;
}

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    UIApplication* application = [UIApplication sharedApplication];
    if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
    {
        UIViewController *c = [[UIViewController alloc]init];
        [c.view setBackgroundColor:[UIColor clearColor]];
        [navigationController presentViewController:c animated:NO completion:^{
            [self dismissViewControllerAnimated:YES completion:^{
            }];
        }];
    }
}
1
LordParsley

SwiftのAlexander( https://stackoverflow.com/posts/25507963/revisions )の答えは次のとおりです。

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {

    var currentViewController: UIViewController? = self.topViewController()
    if currentViewController != nil && currentViewController!.canAutoRotate() {
        return Int(UIInterfaceOrientationMask.All.rawValue)
    }
    return Int(UIInterfaceOrientationMask.Portrait.rawValue)


}

func topViewController() -> UIViewController? {
    if UIApplication.sharedApplication().keyWindow != nil
    {
        return self.topViewControllerWithRootViewController(UIApplication.sharedApplication().keyWindow!.rootViewController!)
    }
    return nil
}

func topViewControllerWithRootViewController(rootViewController: UIViewController?) -> UIViewController? {
    if rootViewController == nil {
        return nil
    }
    if rootViewController!.isKindOfClass(UITabBarController) {
        var tabBarController: UITabBarController = (rootViewController as? UITabBarController)!
        return self.topViewControllerWithRootViewController(tabBarController.selectedViewController)
    }
    else {
        if rootViewController!.isKindOfClass(UINavigationController) {
            var navigationController: UINavigationController = (rootViewController as? UINavigationController)!
            return self.topViewControllerWithRootViewController(navigationController.visibleViewController)
        }
        else {
            if (rootViewController!.presentedViewController != nil) {
                var presentedViewController: UIViewController = rootViewController!.presentedViewController!
                return self.topViewControllerWithRootViewController(presentedViewController)
            }
            else {
                return rootViewController
            }
        }
    }
}

さらに、AppDelegate.Swiftに次のスニペットを追加する必要があります。

extension UIViewController {
func canAutoRotate() -> Bool {
    return false
}}

また、すべての回転を許可するViewControllerの場合、次の関数を追加します。

override func canAutoRotate() -> Bool {
    return true
}
1
egsemsem

//このメソッドをアプリデリゲートクラスに貼り付けます

- (UIInterfaceOrientationMask)application:(UIApplication )application supportedInterfaceOrientationsForWindow:(UIWindow )window
{
 if ([self.window.rootViewController.presentedViewController isKindOfClass: [_moviePlayerController class]])
  {
   if (self.window.rootViewController.presentedViewController)
        return UIInterfaceOrientationMaskAll;
    else return UIInterfaceOrientationMaskPortrait;
  }
 else return UIInterfaceOrientationMaskPortrait;
}   
0
dheerendra

アプリがIOS7からIOS9をサポートしている場合、オリエンテーションにこのコードを使用します。

#if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000
- (NSUInteger)supportedInterfaceOrientations
#else
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
#endif
{
    if([AppDelegate isPad]) return UIInterfaceOrientationMaskAll;
    else return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
}
0
Mihir Oza

この質問は非常に古いものですが、更新された回答が必要です。この結果を達成する最も簡単で最も正しい方法は、アプリの設定でポートレートとランドスケープを有効にすることです。次に、このコードをアプリのデリゲートに追加します。

 func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {

    if let navigationController = self.window?.rootViewController as? UINavigationController {

        if navigationController.visibleViewController is INSERTYOURVIEWCONTROLLERHERE  {
            return UIInterfaceOrientationMask.All
        }

        else {
            return UIInterfaceOrientationMask.Portrait
        }
    }

    return UIInterfaceOrientationMask.Portrait
}

「INSERTYOURVIEWCONTROLLERHERE」をView Controllerに置き換えることを忘れないでください。

0
Paul Lehn

私も同じ状況でした。そこで、UINavigationControllerをCustomNavigationControllerにサブクラス化し、このCustomNavigationController内に次のように書きました。

#define IOS_OLDER_THAN_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] < 6.0 )
#define IOS_NEWER_OR_EQUAL_TO_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 6.0 )


#pragma mark - Rotation

#ifdef IOS_OLDER_THAN_6
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
      return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}
#endif
#ifdef IOS_NEWER_OR_EQUAL_TO_6
-(BOOL)shouldAutorotate {
    return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;;
}
#endif

既存のNavigationControllerではなく、このCustomNavigationControllerを使用しました。

次に、LandScape Orientationに表示する必要があるView Controller内で、LandScapeViewと言います。

#pragma mark - Rotation

#ifdef IOS_OLDER_THAN_6

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
    return (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight | toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

#endif

#ifdef IOS_NEWER_OR_EQUAL_TO_6

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

#endif

CustomNavigationController内で、Navigation Stackにプッシュされるのではなく、このView Controllerを提示しました。そのため、LandScapeViewはLandScape Orientationに表示されました。

LandScapeView *graph = [[LandScapeView alloc]init....];
[self presentViewController:graph animated:YES completion:nil];

プロジェクト設定のサポートされているインターフェイスの向きで何も変更しませんでした。

0
rakeshNS