navigationbar顏色 如何在iOS 8中強制視圖控制器方向?




xcode navigation bar (20)

在iOS 8之前,我們將下面的代碼與supportedInterfaceOrientations以及shouldAutoRotate委託方法結合使用,以強制應用程序定位到任何特定的方向。 我使用下面的代碼片段以編程方式將應用程序旋轉到所需的方向。 首先,我正在改變狀態欄的方向。 然後只是呈現並立即解散模態視圖,將視圖旋轉到所需的方向。

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:YES];
UIViewController *c = [[UIViewController alloc]init];
[self presentViewController:vc animated:NO completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];

但是這在iOS 8中失敗了。另外,我在堆棧溢出中看到了一些答案,人們建議我們應該始終避免從iOS 8開始使用這種方法。

更具體地說,我的應用程序是一種通用類型的應用程序。 總共有三個控制器。

  1. 第一視圖控制器 - 它應該支持iPad中的所有方向,並且只支持iPhone中的肖像(主屏幕按鈕)。

  2. 第二個視圖控制器 - 它應該只支持所有情況下的風景

  3. 第三個視圖控制器 - 它應該只支持所有情況下的景觀權限

我們正在使用導航控制器進行頁面導航。 從第一個視圖控制器,在一個按鈕點擊操作上,我們推動第二個堆棧。 因此,當第二個視圖控制器到達時,無論設備的方向如何,應用程序都應該鎖定在右側。

下面是第二個和第三個視圖控制器中的shouldAutorotatesupportedInterfaceOrientations方法。

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(BOOL)shouldAutorotate {
    return NO;
}

有沒有任何解決方案,或任何更好的方式鎖定視圖控制器在iOS 8的特定方向。請幫助!


我有同樣的問題,浪費了很多時間。 所以現在我有我的解決方案。 我的應用程序設置只是支持肖像。但是,一些屏幕到我的應用程序需要只有風景。我通過在AppDelegate有一個變量isShouldRotate來修復它。 而AppDelegate的功能:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
    if isShouldRotate == true {
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }
    return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}

最後,當ViewControllerA需要橫向狀態時。 只要這樣做: 在推送/呈現ViewControllerA 之前 ,將isShouldRotate賦值true 。 不要忘記當控制器在viewWillDisappear時分配isShouldRotatefalse時彈出/關閉。


[iOS9 +]如果有人因為上述解決方案無法工作而一路拖下來,並且如果您提交的視圖想要通過segue更改方向,則可能需要檢查此問題。

檢查你的segue的演示文稿類型。 礦是'過度的情況下'。 當我將其更改為全屏時,它工作。

感謝@GabLeRoux,我找到了這個解決方案。

  • 此更改僅適用於與上述解決方案結合使用

上面的頂部解決方案:

let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")

當我在視圖控制器的viewDidAppear中調用它時沒有為我工作。 然而,當我在呈現視圖控制器中的preparForSegue中調用它時,它確實有效。

(對不起,沒有足夠的聲望評論該解決方案,所以我不得不像這樣添加它)


我的要求是

  1. 以縱向模式鎖定所有視圖
  2. 使用AVPlayerViewController播放視頻

當播放視頻時,如果是橫屏,則允許屏幕左右旋轉橫向和左橫向。 如果是肖像,那麼只能在肖像模式下鎖定視圖。

首先,在AppDelegate.swift定義supportedInterfaceOrientationsForWindow

var portrait = true
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    if portrait {
        return .Portrait
    } else {
        return .Landscape
    }
}

其次,在您的主視圖控制器中,定義以下功能

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    print("\(#function)")
    return .Portrait
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return .Portrait
}

override func shouldAutorotate() -> Bool {
    return false
}

然後,您需要AVPlayerViewController

class MyPlayerViewController: AVPlayerViewController {

    var size: CGSize?

    var supportedOrientationMask: UIInterfaceOrientationMask?
    var preferredOrientation: UIInterfaceOrientation?

    override func viewDidLoad() {
        super.viewDidLoad()

        if let size = size {
            if size.width > size.height {
                self.supportedOrientationMask =[.LandscapeLeft,.LandscapeRight]
                self.preferredOrientation =.LandscapeRight
            } else {
                self.supportedOrientationMask =.Portrait
                self.preferredOrientation =.Portrait
            }
        }
    }

MyPlayerViewController.swift重寫這三個函數

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return self.supportedOrientationMask!
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return self.preferredOrientation!
}

由於用戶可能會將設備橫向向左或向右橫向旋轉,因此我們需要將自動旋轉設置為true

override func shouldAutorotate() -> Bool {
    return true
}

最後,在視圖控制器中創建MyPlayerViewController實例並設置屬性大小值。

let playerViewController = MyPlayerViewController()

// Get the thumbnail  
let thumbnail = MyAlbumFileManager.sharedManager().getThumbnailFromMyVideoMedia(......)

let size = thumbnail?.size
playerViewController.size = size

用適當的videoUrl啟動你的播放器,然後把你的播放器分配給playerViewController 。 快樂的編碼!


對我而言,頂級VC需要實現方向覆蓋。 如果頂級VC沒有實現,使用VC下的堆棧將不起作用。

VC-main
    |
    -> VC 2
        |
        -> VC 3

只有VC-Main被聽取,基本上在我的測試中。


- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [UIViewController attemptRotationToDeviceOrientation];
}

如果你正在使用navigationViewController,你應該為此創建你自己的超類,並覆蓋:

- (BOOL)shouldAutorotate {
  id currentViewController = self.topViewController;

  if ([currentViewController isKindOfClass:[SecondViewController class]])
    return NO;

  return YES;
}

這將禁用SecondViewController中的旋轉,但如果在設備處於縱向方向時推送SecondViewController ,則SecondViewController將以縱向模式顯示。

假設您正在使用故事板。 您必須創建手動搜索( 如何 )以及“onClick”方法:

- (IBAction)onPlayButtonClicked:(UIBarButtonItem *)sender {
  NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
  [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
  [self performSegueWithIdentifier:@"PushPlayerViewController" sender:self];
}

這會在您的超類禁用自動旋轉功能之前強制進行橫向取向。


Xcode 8這些方法被轉換為屬性,所以以下內容適用於Swift

override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.portrait
}

override public var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return UIInterfaceOrientation.portrait
}

override public var shouldAutorotate: Bool {
    return true
}

首先 - 這是一個壞主意,一般來說,你的應用程序體系結構出了問題,但是,如果是這樣,你可以嘗試做如下的事情:

final class OrientationController {

    static private (set) var allowedOrientation:UIInterfaceOrientationMask = [.all]

    // MARK: - Public

    class func lockOrientation(_ orientationIdiom: UIInterfaceOrientationMask) {
        OrientationController.allowedOrientation = [orientationIdiom]
    }

    class func forceLockOrientation(_ orientation: UIInterfaceOrientation) {
        var mask:UIInterfaceOrientationMask = []
        switch orientation {
            case .unknown:
                mask = [.all]
            case .portrait:
                mask = [.portrait]
            case .portraitUpsideDown:
                mask = [.portraitUpsideDown]
            case .landscapeLeft:
                mask = [.landscapeLeft]
            case .landscapeRight:
                mask = [.landscapeRight]
        }

        OrientationController.lockOrientation(mask)

        UIDevice.current.setValue(orientation.rawValue, forKey: "orientation")
    }
}

比在AppDelegate

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // do stuff
    OrientationController.lockOrientation(.portrait)
    return true
}

// MARK: - Orientation

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return OrientationController.allowedOrientation
}

而且,只要你想改變方向,你可以這樣做:

OrientationController.forceLockOrientation(.landscapeRight)

注意:有時,設備可能無法從此類呼叫更新,因此您可能需要按照以下步驟操作

OrientationController.forceLockOrientation(.portrait)
OrientationController.forceLockOrientation(.landscapeRight)

就這樣


這種方式適用於Swift 2 iOS 8.x中的我:

PS(這種方法不需要覆蓋每個viewController上的shouldautorotate方向函數,只是AppDelegate上的一個方法)

在項目綜合信息中檢查“需要全屏”。

所以,在AppDelegate.swift上創建一個變量:

var enableAllOrientation = false

所以,也放這個func:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
        if (enableAllOrientation == true){
            return UIInterfaceOrientationMask.All
        }
        return UIInterfaceOrientationMask.Portrait
}

所以,在你的項目中的每個類中,你都可以在viewWillAppear中設置這個var:

override func viewWillAppear(animated: Bool)
{
        super.viewWillAppear(animated)
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        appDelegate.enableAllOrientation = true
}

如果你需要根據設備類型做出選擇,你可以這樣做:

override func viewWillAppear(animated: Bool)
    {
        super.viewWillAppear(animated)
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        switch UIDevice.currentDevice().userInterfaceIdiom {
        case .Phone:
        // It's an iPhone
           print(" - Only portrait mode to iPhone")
           appDelegate.enableAllOrientation = false
        case .Pad:
        // It's an iPad
           print(" - All orientation mode enabled on iPad")
           appDelegate.enableAllOrientation = true
        case .Unspecified:
        // Uh, oh! What could it be?
           appDelegate.enableAllOrientation = false
        }
    }

對於iOS 7-10:

Objective-C的:

[[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeLeft) forKey:@"orientation"];
[UINavigationController attemptRotationToDeviceOrientation];

Swift 3:

let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()

只需在視圖控制器的- viewDidAppear:調用它即可。


對於如何最好地完成這項任務似乎還存在一些爭議,所以我想我會分享我的(工作)方法。 在你的UIViewController實現中添加下面的代碼:

- (void) viewWillAppear:(BOOL)animated
{
    [UIViewController attemptRotationToDeviceOrientation];
}

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

-(BOOL)shouldAutorotate
{
    return NO;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscapeLeft;
}

在這個例子中,您還需要在您的項目設置中(或直接在info.plist )將允許的設備方向設置為“橫向左移”。 只需更改您希望強制的特定方向,如果您想要的其他東西不是LandscapeLeft.

對我來說,關鍵是在viewWillAppear attemptRotationToDeviceOrientation調用attemptRotationToDeviceOrientation調用 - 沒有這樣做,如果沒有物理旋轉設備,視圖將不能正確旋轉。


根據@ sid-sha顯示的解決方案,您必須將所有內容放在viewDidAppear:方法中,否則您將無法獲得didRotateFromInterfaceOrientation:如下所示:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
        interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
        NSNumber *value = [NSNumber numberWithInt:interfaceOrientation];
        [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
    }
}

我的解決方案

AppDelegate

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    if let topController = UIViewController.topMostViewController() {
        if topController is XXViewController {
            return [.Portrait, .LandscapeLeft]
        }
    }
    return [.Portrait]
}

XXViewController是您想要支持橫向模式的ViewController。

然後, Sunny Shah的解決方案可以在任何iOS版本的XXViewController上運行:

let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")

這是查找最頂級ViewController的實用程序功能。

extension UIViewController {

    /// Returns the current application's top most view controller.
    public class func topMostViewController() -> UIViewController? {
        let rootViewController = UIApplication.sharedApplication().windows.first?.rootViewController
        return self.topMostViewControllerOfViewController(rootViewController)
    }



    /// Returns the top most view controller from given view controller's stack.
    class func topMostViewControllerOfViewController(viewController: UIViewController?) -> UIViewController? {
        // UITabBarController
        if let tabBarController = viewController as? UITabBarController,
           let selectedViewController = tabBarController.selectedViewController {
            return self.topMostViewControllerOfViewController(selectedViewController)
        }

        // UINavigationController
        if let navigationController = viewController as? UINavigationController,
           let visibleViewController = navigationController.visibleViewController {
            return self.topMostViewControllerOfViewController(visibleViewController)
        }

        // presented view controller
        if let presentedViewController = viewController?.presentedViewController {
            return self.topMostViewControllerOfViewController(presentedViewController)
        }

        // child view controller
        for subview in viewController?.view?.subviews ?? [] {
            if let childViewController = subview.nextResponder() as? UIViewController {
                return self.topMostViewControllerOfViewController(childViewController)
            }
        }

        return viewController
    }

}


我已經嘗試了很多解決方案,但是有效的解決方案如下:

不需要編輯ios 8和9中的info.plist

- (BOOL) shouldAutorotate {
    return NO;
}   

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return (UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown);
}

Apple文檔可能的方向

UIInterfaceOrientationUnknown

設備的方向無法確定。

UIInterfaceOrientationPortrait

該設備處於肖像模式,設備保持直立,底部的主頁按鈕。

UIInterfaceOrientationPortraitUpsideDown

該設備處於縱向模式,但倒置,設備保持直立,頂部的主頁按鈕。

UIInterfaceOrientationLandscapeLeft

設備處於橫向模式,設備保持直立,左側的主頁按鈕。

UIInterfaceOrientationLandscapeRight

設備處於橫向模式,設備直立並且主頁按鈕位於右側。


使用它來鎖定視圖控制器方向,並在IOS 9上測試:

//將方向鎖定到右側

-(UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscapeRight;
}

-(NSUInteger)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController {
    return UIInterfaceOrientationMaskLandscapeRight;
}

我在這裡嘗試了一些解決方案,需要了解的重要一點是它是根視圖控制器,它將確定它是否會旋轉。

我使用TabbedViewController一個工作示例創建了以下objective-c項目github.com/GabLeRoux/RotationLockInTabbedViewChild ,其中一個子視圖被允許旋轉,另一個子視圖被鎖定在肖像中。

這不是完美的,但它的工作原理和相同的想法應該適用於其他類型的根視圖,如NavigationViewController 。 :)


我發現如果它是一個呈現的視圖控制器,則可以覆蓋preferredInterfaceOrientationForPresentation

迅速:

override func supportedInterfaceOrientations() -> Int {
  return Int(UIInterfaceOrientationMask.Landscape.rawValue)
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
  return UIInterfaceOrientation.LandscapeLeft
}

override func shouldAutorotate() -> Bool {
  return false
}

如果您位於UINavigationControllerUITabBarController則方向旋轉稍微複雜一些。 問題是,如果視圖控制器嵌入在其中一個控制器中,則導航或選項卡欄控制器將優先考慮並決定自動旋轉和支持的方向。

我在UINavigationController和UITabBarController上使用以下兩個擴展,以便嵌入在這些控制器之一中的視圖控制器可以做出決定。

賦予視圖控制器強大功能!

Swift 2.3

extension UINavigationController {
    public override func supportedInterfaceOrientations() -> Int {
        return visibleViewController.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        return visibleViewController.shouldAutorotate()
    }
}

extension UITabBarController {
    public override func supportedInterfaceOrientations() -> Int {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations()
        }
        return super.supportedInterfaceOrientations()
    }
    public override func shouldAutorotate() -> Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate()
        }
        return super.shouldAutorotate()
    }
}

斯威夫特3

extension UINavigationController {
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return visibleViewController?.supportedInterfaceOrientations ?? super.supportedInterfaceOrientations
    }

    open override var shouldAutorotate: Bool {
        return visibleViewController?.shouldAutorotate ?? super.shouldAutorotate
    }
}

extension UITabBarController {
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if let selected = selectedViewController {
            return selected.supportedInterfaceOrientations
        }
        return super.supportedInterfaceOrientations
    }

    open override var shouldAutorotate: Bool {
        if let selected = selectedViewController {
            return selected.shouldAutorotate
        }
        return super.shouldAutorotate
    }
}

現在,您可以覆蓋supportedInterfaceOrientations方法,或者您可以覆蓋要鎖定的視圖控制器中的shouldAutoRotate ,否則可以忽略其他視圖控制器中的覆蓋,這些視圖控制器要繼承應用程序的plist中指定的默認方向行為

禁用旋轉

class ViewController: UIViewController {
    override func shouldAutorotate() -> Bool {
        return false
    }
}

鎖定特定的方向

class ViewController: UIViewController {
    override func supportedInterfaceOrientations() -> Int {
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }
}

理論上這應該適用於所有復雜的視圖控制器層次結構,但我注意到UITabBarController存在一個問題。 出於某種原因,它想要使用默認方向值。 如果您有興趣了解如何解決某些問題,請參閱以下博文:

鎖屏旋轉





autorotate