iphone - iOS 6:我如何限制一些視圖到肖像並允許其他人旋轉?




ios6 autorotate (13)

我有一個iPhone應用程序,它使用UINavigationController來呈現下鑽界面:第一個視圖,然後是另一個視圖,深度最多達四級。 我希望將前三個視圖限制為縱向,並且只允許最後一個視圖旋轉到橫向。 當從第四個視圖返回到第三個視圖並且第四個視圖處於橫向時,我希望所有內容都可以旋轉回肖像。

在iOS 5中,我簡單地定義了shouldAutorotateToInterfaceOrientation:在每個視圖控制器中為允許的方向返回YES。 如上所述,所有操作都可以正常進行,包括即使從視圖控制器#4返回到#3時橫向保持設備,也返回肖像。

在iOS 6中,所有視圖控制器都會旋轉到橫向,打破那些並非如此。 iOS 6發行說明說

更多的責任是轉向應用程序和應用程序委託。 現在,iOS容器(例如UINavigationController )不會諮詢他們的孩子以確定他們是否應該自動旋轉。 [...]無論何時設備旋轉或每當視圖控制器呈現全屏模式演示風格時,系統都會詢問其支持的接口方向的最頂級全屏視圖控制器(通常是根視圖控制器)。 此外,只有當此視圖控制器從其shouldAutorotate方法返回YES時,才會檢索支持的方向。 [...]系統通過將應用程序的supportedInterfaceOrientationsForWindow:方法返回的值與最頂級全屏控制器的supportedInterfaceOrientations方法返回的值相交來確定是否支持方向。

所以我subclassed UINavigationController ,給我的MainNavigationController一個布爾屬性landscapeOK並用它來返回在supportedInterfaceOrientations允許的方向。 然後在我的每個視圖控制器的viewWillAppear:方法中,我有這樣一行

    [(MainNavigationController*)[self navigationController] setLandscapeOK:YES];

告訴我的MainNavigationController所需的行為。

問題在於:如果我現在導航到縱向模式下的第四個視圖,然後翻轉手機,則旋轉到橫向。 現在我按下後退按鈕返回到我的第三個視圖,該視圖只應用於肖像。 但它不會迴轉。 我該如何做到這一點?

我試過了

    [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait]

在我的第三個視圖控制器的viewWillAppear方法中,但它沒有做任何事情。 這是調用錯誤的方法還是錯誤的地方來調用它,或者我應該以完全不同的方式實現整個事情?


Answers

這是我用於ios 6.0中的定位支持

-(BOOL)shouldAutorotate{
    return YES;
}  

 - (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskAll;
}


- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{  
  return UIInterfaceOrientationPortrait;
}

我面臨同樣的問題。 並解決了我的問題,如下所示。

如果您使用UINavigationController來推視圖控制器,那麼您必須設置下面的方法。

extension UINavigationController{


override open var shouldAutorotate: Bool {

    if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))!
    {
        return true
    }
    return false
}

override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {

    if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))!
    {
        return .portrait
    }
    return .landscapeRight

}
override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {

    if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))!
    {
        return .portrait
    }
    return .landscapeRight
}

}

代替LoginViewController使用你想要顯示的UIViewController 。 在我的情況下,我想在Portrait模式下以Portrait模式顯示其他ViewControllersLoginViewController


在對所有關於SO的類似問題進行回答後,沒有任何答案適用於我,但他們確實給了我一些想法。 以下是我最終解決問題的方法:

首先,確保項目目標中的支持的界面方向包含您想要旋轉視圖的所有方向。

接下來,創建一個UINavigationController的類別(因為Apple說不要繼承它):

@implementation UINavigationController (iOS6AutorotationFix)

-(BOOL)shouldAutorotate {
    return [self.topViewController shouldAutorotate];
}

@end

將您想要旋轉的類別和視圖控制器(我將調用RotatingViewController )導入到最高級別的視圖控制器,該視圖控制器應包含您的導航控制器。 在該視圖控制器中,執行如下所示的操作。 請注意,這不應該與您想要旋轉的視圖控制器相同。

-(BOOL)shouldAutorotate {

    BOOL shouldRotate = NO;

    if ([navigationController.topViewController isMemberOfClass:[RotatingViewController class]] ) {
        shouldRotate = [navigationController.topViewController shouldAutorotate];
    }

    return shouldRotate;
}

最後,在你的RotatingViewController ,實現shouldAutorotatesupportedInterfaceOrientations ,如下所示:

-(BOOL)shouldAutorotate {
    // Preparations to rotate view go here
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskAllButUpsideDown; // or however you want to rotate
}

你需要這樣做的原因是因為iOS 6可以控制旋轉到根視圖控制器而不是頂視圖控制器。 如果您希望單個視圖的旋轉行為與堆棧中其他視圖的行為不同,則需要在根視圖控制器中為其編寫特定的案例。


這可能不適用於所有人,但它對我來說很好。 而不是實施...

[(MainNavigationController*)[self navigationController] setLandscapeOK:YES];

在viewWillAppear中,我決定通過重寫UINavigationControllerDelegate方法navigationController:willShowViewController:animated:來集中處理我的UINavigationController子類中的這個進程navigationController:willShowViewController:animated:

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {

    self.previousVCLandscapeOK = self.isLandscapeOK; // Store the current VC's orientation preference before pushing on the new VC so we can set this again from within the custom "back" method
    self.isLandscapeOK = NO; // Set NO as default for all VC's
    if ([viewController isKindOfClass:[YourViewController class]]) {
        self.isLandscapeOK = YES;
    }
}

我發現當從導航堆棧彈出一個VC時,這個委託方法不會被調用。 這對我來說不是問題,因為我在我的UINavigationController子類中處理後台功能,以便我可以為特定的VC設置正確的導航欄按鈕和操作,如下所示...

if ([viewController isKindOfClass:[ShareViewController class]]) {

    UIButton* backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 57, 30)];
    [backButton setImage:[UIImage imageNamed:@"back-arrow"] forState:UIControlStateNormal];
    [backButton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
    UIBarButtonItem* backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
    viewController.navigationItem.leftBarButtonItem = backButtonItem;

    UIImageView* shareTitle = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"share-title"]];
    [shareTitle setContentMode:UIViewContentModeScaleAspectFit];
    [shareTitle setFrame:CGRectMake(0, 0, shareTitle.frame.size.width - 10, shareTitle.frame.size.height - 10)];
    viewController.navigationItem.titleView = shareTitle;

} else if(...) {
    ...
}

這裡是我的back方法看起來像處理從堆棧彈出VC並設置適當的旋轉首選項...

- (void)back {
    self.isLandscapeOK = self.previousVCLandscapeOK;
    self.previousVCLandscapeOK = NO;
    [self popViewControllerAnimated:YES];
}

所以,正如你所看到的,基本上所有的事情都是我第一次設定了兩個屬性......

@property (nonatomic) BOOL isLandscapeOK;
@property (nonatomic) BOOL previousVCLandscapeOK;

navigationController:willShowViewController:animated:它將確定哪些支持的方向在即將展示的VC內。 當彈出一個VC時,我的自定義“後退”方法被調用,然後我將isLandscapeOK設置為通過之前的VCLandscapeOK值存儲的內容。

正如我所說,這可能不適用於所有人,但它對我很好,我不必擔心向每個視圖控制器添加代碼,我可以將它全部集中在UINavigationController子類中。

希望這可以幫助像我這樣做的人。 謝謝,傑里米。


我想讓所有的VC都鎖定在肖像方向,除了一個。 這對我來說很有用。

  1. 添加對plist文件中所有方向的支持。
  2. 在根視圖控制器中,檢測窗口頂部的視圖控制器的類型,並相應地在supportedInterfaceOrientations方法中設置應用程序的方向。 例如,我需要我的應用程序只在webview位於堆棧頂部時進行旋轉。 以下是我在rootVC中添加的內容:

    -(NSUInteger)supportedInterfaceOrientations
    {
        UIViewController *topMostViewController = [[Utils getAppDelegate] appNavigationController].topViewController;
        if ([topMostViewController isKindOfClass:[SVWebViewController class]]) {
            return UIInterfaceOrientationMaskAllButUpsideDown;
        }
        return UIInterfaceOrientationMaskPortrait;
    }
    

您可以在所有視圖控制器類中實現並覆蓋shouldAutorotate()和supportedInterfaceOrientations var,該類應以與應用程序的PLIST中定義的方向不同的方向呈現。

但是,在一個非常重要的用戶界面中,您可能會遇到將其添加到數十個類中的問題,並且您不希望將它們全部用於支持它的幾個常見子類(MyBaseTableViewController,MyBaseNavigationController和MyBaseTabBarController)。

既然你不能直接在UIViewController上覆蓋這些方法/ var,你可以在它的子類中這樣做,這些子類通常是你的基類,如UITableViewController,UINavigationController和UITabBarController。

所以你可以實現一些擴展,並且仍然設置MyPreciousViewController以不同於所有其他方式顯示Swift 4代碼片段:

extension UITableViewController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {

    if let last = self.navigationController?.childViewControllers.last,
        last != self {
            return last.supportedInterfaceOrientations
    } else {
        return [.portrait]
    }
    }
}

extension MyPreciousViewController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {

    return [.portrait,.landscape]
    }
}


extension UINavigationController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {

        return [.portrait]
    }
}


extension UITabBarController {
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {

        return [.portrait]
    }
}

我遇到了同樣的問題,並找到了適合我的解決方案。 為了使它工作,在UINavigationController中實現- (NSUInteger)supportedInterfaceOrientations是不夠的。 你還需要在你的控制器#3中實現這個方法,這是第一個在彈出控制器#4之後才是肖像的方法。 所以,我在我的UINavigationController中有以下代碼:

- (BOOL)shouldAutorotate
{
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    if (self.isLandscapeOK) {
        // for iPhone, you could also return UIInterfaceOrientationMaskAllButUpsideDown
        return UIInterfaceOrientationMaskAll;
    }
    return UIInterfaceOrientationMaskPortrait;
}

在視圖控制器#3中添加以下內容:

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

你不需要添加任何東西到你的視圖控制器#1,#2和#4。 這對我有用,我希望它能幫助你。


轉到Info.plist文件並進行更改


我沒有足夠的聲望評論@ Brian的答案,所以我會在這裡添加我的記錄。

Brian提到iOS6給了rootViewController旋轉控制 - 這不僅可以像上面提到的那樣是UINavigationController,而且可以是UITabBarController,這對我來說也是如此。 我的結構如下所示:

  • 的UITabBarController
    • UINavigationController的
      • UIViewControllers ...
    • UINavigationController的
      • UIViewControllers ...

所以我首先在自定義的UITabBarController中添加了方法,然後在自定義的UINavigationController中添加了方法,最後在特定的UIViewController中添加了方法。

來自UITabBarController和UINavigationController的示例:

- (BOOL)shouldAutorotate {
    return [self.viewControllers.lastObject shouldAutorotate];
}

- (NSUInteger)supportedInterfaceOrientations {
    return [self.viewControllers.lastObject supportedInterfaceOrientations];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return [self.viewControllers.lastObject shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    return [self.viewControllers.lastObject preferredInterfaceOrientationForPresentation];
}

您只需要強制iOS 6應用程序縱向即可添加到UIViewController子類下面的方法

- (BOOL)shouldAutorotate {
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        return YES;
    } else {
        return NO;
    }
}


- (NSUInteger)supportedInterfaceOrientations {
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        return UIInterfaceOrientationMaskAll;
    } else {
        return UIInterfaceOrientationMaskPortrait;
    }
}

添加一個CustomNavigationController

重寫這些方法:

-(BOOL)shouldAutorotate
{
    return [[self.viewControllers lastObject] shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations
{
    return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}

現在在plist中添加所有的方向

在視圖控制器中只添加需要的:

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

這些方法會覆蓋導航控制器方法


請使用以下方法解決此問題

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

只返回你想要的方向!


我有一個非常類似的問題。 除了播放視頻外,我想在任何地方強制使用肖像模式。

我做的是:

1)在AppDelegate中強制app方向為縱向:

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    if ([window.rootViewController.presentedViewController isKindOfClass:[MPMoviePlayerViewController class]])
    {
        return UIInterfaceOrientationMaskAll;
    }
    return UIInterfaceOrientationMaskPortrait;
}

2)啟動一個空的模態視圖控制器修復了我的問題。 我在第一個視圖控制器的viewDidLoad中啟動它,它位於我的NavigationViewController的根目錄(應用程序啟動後可見的第一個視圖控制器):

- (void)showAndHideNamelessViewControllerToFixOrientation {
    UIViewController* viewController = [[UIViewController alloc] init];
    [self presentViewController:viewController animated:NO completion:nil];
    [viewController dismissViewControllerAnimated:NO completion:nil];
}






iphone ios6 autorotate