如何锁定方向的一个视图控制器的纵向模式只在迅捷

由于我的应用程序获得了所有方向的支持。我想锁定只有肖像模式的特定 UIViewController。

例如,假设它是选项卡式应用程序,当 SignIn 视图以模态方式出现时,我只希望 SignIn 视图处于纵向模式,而不管用户如何旋转设备或当前设备方向如何

151744 次浏览

添加此代码以强制肖像并锁定它:

override func viewDidLoad() {
super.viewDidLoad()


// Force the device in portrait mode when the view controller gets loaded
UIDevice.currentDevice().setValue(UIInterfaceOrientation.Portrait.rawValue, forKey: "orientation")
}


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


override func supportedInterfaceOrientations() -> Int {


// Only allow Portrait
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}


override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {


// Only allow Portrait
return UIInterfaceOrientation.Portrait
}

在你的应用程序代表集 support tedInterfaceOrientationsForWindow 中,你希望整个应用程序支持的任何方向:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.All
}

要设置横向方向所有视图的应用程序和只允许一个视图的所有方向(能够添加相机辊例如) :

迅速:

var adaptOrientation = false

在: did FinishLaunchingWithOptions

NSNotificationCenter.defaultCenter().addObserver(self, selector: "adaptOrientationAction:", name:"adaptOrientationAction", object: nil)

迅速:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
return checkOrientation(self.window?.rootViewController)
}


func checkOrientation(viewController:UIViewController?)-> Int{
if (adaptOrientation == false){
return Int(UIInterfaceOrientationMask.Landscape.rawValue)
}else {
return Int(UIInterfaceOrientationMask.All.rawValue)
}
}


func adaptOrientationAction(notification: NSNotification){
if adaptOrientation == false {
adaptOrientation = true
}else {
adaptOrientation = false
}
}

然后,在继续你希望能够拥有所有方向的观点中:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "YOURSEGUE") {
NSNotificationCenter.defaultCenter().postNotificationName("adaptOrientationAction", object: nil)
}
}


override func viewWillAppear(animated: Bool) {
if adaptOrientation == true {
NSNotificationCenter.defaultCenter().postNotificationName("adaptOrientationAction", object: nil)
}
}

最后一件事是勾选设备方向: 肖像 - 左侧景观 - 园景右图

当您有一个复杂的视图层次结构时,事情可能会变得相当混乱,比如拥有多个导航控制器和/或选项卡视图控制器。

这个实现将它放在各个视图控制器上,以便在它们希望锁定方向时进行设置,而不是依赖于 App Generate 通过迭代子视图来查找它们。

斯威夫特345

返回文章页面应用代表:

/// set orientations you want to be allowed in this property by default
var orientationLock = UIInterfaceOrientationMask.all


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

在其他一些全局结构或助手类中,我在这里创建了 AppUtility:

struct AppUtility {


static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
    

if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}


/// OPTIONAL Added method to adjust lock and rotate to the desired orientation
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
   

self.lockOrientation(orientation)
    

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


}

然后在所需的 ViewController 中锁定方向:

 override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
    

AppUtility.lockOrientation(.portrait)
// Or to rotate and lock
// AppUtility.lockOrientation(.portrait, andRotateTo: .portrait)
    

}


override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
    

// Don't forget to reset when view is being removed
AppUtility.lockOrientation(.all)
}

如果 iPad 或通用应用程序

确保在目标设置-> 一般-> 部署信息中勾选“需要全屏”。如果未选中 supportedInterfaceOrientationsFor委托,则不会调用该委托。 enter image description here

你是我的救命恩人,这是唯一可行的解决方案(使用 AppUtilitystruct)

我创建了这个类:

class Helper{
struct AppUtility {


static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {


if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}


/// OPTIONAL Added method to adjust lock and rotate to the desired orientation
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {


self.lockOrientation(orientation)


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


}
}

并按照您的指示,一切工作完美的 Swift 3-> xcode 版本8.2.1

这个帖子里有很多很棒的答案,但是没有一个完全符合我的需要。我有一个选项卡应用程序与导航控制器在每个选项卡,一个视图需要旋转,而其他需要锁定在纵向。由于某些原因,导航控制器没有正确地调整子视图的大小。通过与 这个答案结合找到了解决方案(在 Swift 3中) ,布局问题消失了。按照@bmjohns 的建议创建 struct:

import UIKit


struct OrientationLock {


static func lock(to orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}


static func lock(to orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation: UIInterfaceOrientation) {
self.lock(to: orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}

然后子类 UITabBarController:

    import UIKit


class TabBarController: UITabBarController, UITabBarControllerDelegate {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.delegate = self
}


func tabBarControllerSupportedInterfaceOrientations(_ tabBarController: UITabBarController) -> UIInterfaceOrientationMask {
if tabBarController.selectedViewController is MyViewControllerNotInANavigationControllerThatShouldRotate {
return .allButUpsideDown
} else if let navController = tabBarController.selectedViewController as? UINavigationController, navController.topViewController is MyViewControllerInANavControllerThatShouldRotate {
return .allButUpsideDown
} else {
//Lock view that should not be able to rotate
return .portrait
}
}


func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if viewController is MyViewControllerNotInANavigationControllerThatShouldRotate {
OrientationLock.lock(to: .allButUpsideDown)
} else if let navController = viewController as? UINavigationController, navController.topViewController is MyViewControllerInANavigationControllerThatShouldRotate {
OrientationLock.lock(to: .allButUpsideDown)
} else {
//Lock orientation and rotate to desired orientation
OrientationLock.lock(to: .portrait, andRotateTo: .portrait)
}
return true
}
}

不要忘记将故事板中 TabBarController 的类更改为新创建的子类。

这是针对您的问题和其他相关问题的通用解决方案。

1. 创建辅助类 UIHelper 并使用以下方法:

    /**This method returns top view controller in application  */
class func topViewController() -> UIViewController?
{
let helper = UIHelper()
return helper.topViewControllerWithRootViewController(rootViewController: UIApplication.shared.keyWindow?.rootViewController)
}


/**This is a recursive method to select the top View Controller in a app, either with TabBarController or not */
private func topViewControllerWithRootViewController(rootViewController:UIViewController?) -> UIViewController?
{
if(rootViewController != nil)
{
// UITabBarController
if let tabBarController = rootViewController as? UITabBarController,
let selectedViewController = tabBarController.selectedViewController {
return self.topViewControllerWithRootViewController(rootViewController: selectedViewController)
}


// UINavigationController
if let navigationController = rootViewController as? UINavigationController ,let visibleViewController = navigationController.visibleViewController {
return self.topViewControllerWithRootViewController(rootViewController: visibleViewController)
}


if ((rootViewController!.presentedViewController) != nil) {
let presentedViewController = rootViewController!.presentedViewController;
return self.topViewControllerWithRootViewController(rootViewController: presentedViewController!);
}else
{
return rootViewController
}
}


return nil
}

2. 根据你的愿望行为创建一个协议,因为你的具体情况将被描绘出来。

协议方向是唯一的肖像{}

注意: 如果需要,可以将它添加到 UIHelper 类的顶部。

3. 扩展视图控制器

就你而言:

class Any_ViewController: UIViewController,orientationIsOnlyPortrait {


....


}

4. 在应用程序委托类中添加以下方法:

 func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
let presentedViewController = UIHelper.topViewController()
if presentedViewController is orientationIsOnlyPortrait {
return .portrait
}
return .all
}

最后说明:

  • 如果更多的类处于纵向模式,只需扩展它 规定。
  • 如果希望从视图控制器获得其他行为,请创建其他协议并遵循相同的结构。
  • 这个例子解决了按下之后方向改变的问题 视图控制器

感谢上面@bmjohn 的回答。下面是这个答案代码的工作 Xamarin/C # 版本,以节省其他人的抄写时间:

AppGenerate.cs

 public UIInterfaceOrientationMask OrientationLock = UIInterfaceOrientationMask.All;
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, UIWindow forWindow)
{
return this.OrientationLock;
}

静电 orientationutility.cs 类别:

public static class OrientationUtility
{
public static void LockOrientation(UIInterfaceOrientationMask orientation)
{
var appdelegate = (AppDelegate) UIApplication.SharedApplication.Delegate;
if(appdelegate != null)
{
appdelegate.OrientationLock = orientation;
}
}


public static void LockOrientation(UIInterfaceOrientationMask orientation, UIInterfaceOrientation RotateToOrientation)
{
LockOrientation(orientation);


UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)RotateToOrientation), new NSString("orientation"));
}
}

视图控制器:

    public override void ViewDidAppear(bool animated)
{
base.ViewWillAppear(animated);
OrientationUtility.LockOrientation(UIInterfaceOrientationMask.Portrait, UIInterfaceOrientation.Portrait);
}


public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
OrientationUtility.LockOrientation(UIInterfaceOrientationMask.All);
}

在 iOS10和 iOS11中,iPad 支持幻灯片切换和分割视图。要启用幻灯片和分割视图中的应用程序,取消选中 Requires full screen 必须的。这意味着接受的答案不能使用 如果的应用程序希望支持幻灯片和分割视图。更多信息请见苹果的 在 iPad 上采用多任务增强功能 给你

我有一个解决方案,允许(1)取消选中 Requires full screen,(2)只在 appDelegate中实现一个函数(特别是如果你不想/不能修改目标视图控制器) ,(3)避免递归调用。不需要助手类或扩展。

(Swift 4)

func application(_ application: UIApplication,
supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
// Search for the visible view controller
var vc = window?.rootViewController
// Dig through tab bar and navigation, regardless their order
while (vc is UITabBarController) || (vc is UINavigationController) {
if let c = vc as? UINavigationController {
vc = c.topViewController
} else if let c = vc as? UITabBarController {
vc = c.selectedViewController
}
}
// Look for model view controller
while (vc?.presentedViewController) != nil {
vc = vc!.presentedViewController
}
print("vc = " + (vc != nil ? String(describing: type(of: vc!)) : "nil"))
// Final check if it's our target class.  Also make sure it isn't exiting.
// Otherwise, system will mistakenly rotate the presentingViewController.
if (vc is TargetViewController) && !(vc!.isBeingDismissed) {
return [.portrait]
}
return [.all]
}

剪辑

@ bmjohns 指出这个函数在 iPad 上不会被调用。我核实过了,是的,没有叫这个名字。所以,我又做了一些测试,发现了一些事实:

  1. 我没有选中 Requires full screen,因为我想在 iPad 上启用幻灯片切换和幻灯片视图。这要求应用程序支持所有4个方向的 iPad,在 Info.plist: Supported interface orientations (iPad)

我的应用程序和 Facebook 的工作方式一样: 在 iPhone 上,大多数时候它都是锁定为肖像的。当查看全屏图像时,允许用户旋转景观以获得更好的视野。在 iPad 上,用户可以在任何视图控制器中旋转到任何方向。所以,当 iPad 放在 Smart Cover (左边的风景图)上时,这个应用程序看起来很漂亮。

  1. 对于调用 application(_:supportedInterfaceOrientationsFor)的 iPad,在 Info.plist 中,只保留 iPad 的肖像。该应用程序将失去滑过 + 分割查看能力。但是您可以锁定或解锁任何视图控制器的方向,只需要在一个地方,不需要修改 ViewController 类。

  2. 最后,当视图显示/删除时,在视图控制器的生命周期中调用此函数。如果您的应用程序需要在其他时间锁定/解锁/改变方向,它可能无法工作

斯威夫特4/5

工程项目-> 一般资料 enter image description here 应用代理

var orientationLock = UIInterfaceOrientationMask.all
    

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return self.orientationLock
}
struct AppUtility {
static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
        

static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
self.lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}

您的 ViewController 如果只需要纵向方向,请添加以下行。您必须将此应用到所有 ViewController 需要显示肖像模式的地方。

override func viewWillAppear(_ animated: Bool) {
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.portrait, andRotateTo: UIInterfaceOrientation.portrait)
}

根据设备物理方向为其他 Viewcontroller 制作屏幕方向。

override func viewWillDisappear(_ animated: Bool) {
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.all)
}

用。创建新的扩展

import UIKit


extension UINavigationController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
}


extension UITabBarController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
}

的实际测试解决方案。在我的例子中,我需要我的整个应用程序应该在纵向模式,但只有一个屏幕的方向应该在横向模式。 Make a Portrait orientation for app , by check only portrait mode

如上所述,在应用委托中编写代码。

var orientationLock = UIInterfaceOrientationMask.all


func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask
{
return self.orientationLock
}
struct AppUtility {


static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
self.lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}

然后写下这个代码之前,您的横向方向视图控制器将提出/推。

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.portrait, andRotateTo: UIInterfaceOrientation.portrait)
}

然后在实际的视图控制器中写下这段代码(用于横向视图)

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.landscape, andRotateTo: UIInterfaceOrientation.landscape)
}

Swift 3 & 4

像下面这样设置特定 UIViewController 的 supportedInterfaceOrientations属性:

class MyViewController: UIViewController {


var orientations = UIInterfaceOrientationMask.portrait //or what orientation you want
override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
get { return self.orientations }
set { self.orientations = newValue }
}


override func viewDidLoad() {
super.viewDidLoad()
}


//...
}

更新

这个解决方案只有在 viewController是嵌入在 UINavigationController中的 没有时才有效,因为方向继承自父 viewController。
对于这种情况,您可以创建 UINavigationViewController的子类并在其上设置这些属性。

这里有一个简单的方法,适用于我的 Swift 4.2(iOS 12.2) ,把它放在 UIViewController中,你想禁用 should dAutorotate:

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}

.portrait部分告诉它保持在哪个方向,您可以随意更改。选择是: .portrait.all.allButUpsideDown.landscape.landscapeLeft.landscapeRight.portraitUpsideDown

我做了一些实验,设法为这个问题找到了干净的解决方案。 该方法基于通过 view-> tag 的视图标记

在目标 ViewController 中,只需将标记分配给根视图,如下面的代码示例所示:

class MyViewController: BaseViewController {


// declare unique view tag identifier
static let ViewTag = 2105981;


override func viewDidLoad()
{
super.viewDidLoad();
// assign the value to the current root view
self.view.tag = MyViewController.ViewTag;
}

最后,快速检查当前显示的视图是否是我们标记的视图:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask
{
if (window?.viewWithTag(DesignerController.ViewTag)) != nil {
return .portrait;
}
return .all;
}

这种方法已经在我的模拟器上进行了测试,看起来效果不错。

注意: 如果当前 MVC 与导航堆栈中的某个子 ViewController 重叠,也会找到标记的视图。

对于一个新版本的斯威夫特试试这个

override var shouldAutorotate: Bool {
return false
}


override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.portrait
}


override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return UIInterfaceOrientation.portrait
}

最佳解决方案锁定和改变方向的纵向和横向:

观看 YouTube 上的视频:

Https://m.youtube.com/watch?v=4vrrhdbowyo

本教程是最好的和简单的。

或使用以下代码:

看这张照片

//1-在第二个视图控制器中,我们设置景观左边,在第一个视图控制器中,我们设置肖像:

//2-如果使用 NavigationController,则应该添加扩展名

import UIKit


class SecondViewController: UIViewController {




override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")
}


override open var shouldAutorotate: Bool {
return false
}


override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .landscapeLeft
}


override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return .landscapeLeft
}
    

    



override func viewDidLoad() {
super.viewDidLoad()
}


//write The rest of your code in here




}


//if you use NavigationController, you should add this extension


extension UINavigationController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return topViewController?.supportedInterfaceOrientations ?? .allButUpsideDown
    

}
}