由于我的应用程序获得了所有方向的支持。我想只将肖像模式锁定到特定的UIViewController。
(例如,假设它是Tabbed应用程序,当SignIn View以模态方式出现时,我只希望SignIn View只能进入纵向模式 无论用户如何旋转设备或当前设备如何 方向将是)
答案 0 :(得分:186)
当您拥有复杂的视图层次结构时,例如拥有多个导航控制器和/或制表视图控制器,事情会变得非常混乱。
此实现将它放在各个视图控制器上,以设置何时锁定方向,而不是依靠App Delegate通过迭代子视图来查找它们。
Swift 3& 4 强>
在AppDelegate中:
/// 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
}
在其他一些全局struct或helper类中,我在这里创建了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
委托将不会被调用。
答案 1 :(得分:16)
Swift 4
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)
}
答案 2 :(得分:9)
对于Swift的新版本,请尝试
override var shouldAutorotate: Bool {
return false
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.portrait
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return UIInterfaceOrientation.portrait
}
答案 3 :(得分:8)
添加此代码以强制纵向并锁定它:
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
}
在AppDelegate中 - 将supportedInterfaceOrientationsForWindow设置为您希望整个应用程序支持的任何方向:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.All
}
答案 4 :(得分:5)
这是针对您的问题和其他相关问题的通用解决方案。
<强> 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。根据您的愿望行为创建一个协议,因为您的具体情况将是肖像。
protocol orientationIsOnlyPortrait {}
Nota:如果需要,请将其添加到UIHelper类的顶部。
第3。扩展视图控制器
在你的情况下:
class Any_ViewController: UIViewController,orientationIsOnlyPortrait {
....
}
<强> 4。在app delegate类中添加此方法:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
let presentedViewController = UIHelper.topViewController()
if presentedViewController is orientationIsOnlyPortrait {
return .portrait
}
return .all
}
最终备注:
答案 5 :(得分:4)
这个帖子中有很多很棒的答案,但没有一个能满足我的需求。我有一个带标签的应用程序,每个选项卡中都有导航控制器,需要旋转一个视图,而其他视图需要以纵向锁定。由于某种原因,导航控制器没有正确调整其子视图的大小。通过结合this答案找到解决方案(在Swift 3中),布局问题消失了。按@bmjohns:
创建结构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的类更改为新创建的子类。
答案 6 :(得分:2)
将横向设置为应用的所有视图&amp;只允许一个视图到所有方向(例如,能够添加相机胶卷):
在AppDelegate.swift中:
var adaptOrientation = false
In:didFinishLaunchingWithOptions
NSNotificationCenter.defaultCenter().addObserver(self, selector: "adaptOrientationAction:", name:"adaptOrientationAction", object: nil)
AppDelegate.swift中的其他地方:
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)
}
}
最后一件事是勾选设备方向: - 肖像 - 左侧风景 - 风景正确
答案 7 :(得分:2)
快速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()
}
//...
}
答案 8 :(得分:1)
bmjohns - &gt;你是我生命的救星。这是唯一可行的解决方案(使用AppUtility结构)
我创建了这个类:
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 - &gt; xcode版本8.2.1
答案 9 :(得分:1)
从iOS 10和11开始,iPad支持Slide Over和Split View。要在幻灯片放映和拆分视图中启用应用,必须取消选中Requires full screen
。这意味着如果应用程序想要支持幻灯片放映和拆分视图,则无法使用接受的答案。了解更多Apple的在iPad上采用多任务处理增强功能 here。
我有一个解决方案,允许(1)取消选中Requires full screen
,(2)只需在appDelegate
中实施一项功能(特别是如果你不想/可以&#39; t修改目标视图控制器),以及(3)避免递归调用。不需要帮助类也不需要扩展。
appDelegate.swift (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上没有调用此功能。我验证了,是的,它没有被调用。所以,我做了一些测试,发现了一些事实:
Requires full screen
,因为我想在iPad上启用幻灯片放映和幻灯片放映。这要求应用程序在Info.plist中支持iPad的所有4个方向:Supported interface orientations (iPad)
。我的应用程序与Facebook的工作方式相同:在iPhone上,大部分时间它都被锁定为肖像。在全屏查看图像时,允许用户旋转横向以获得更好的视图。在iPad上,用户可以在任何视图控制器中旋转到任何方向。所以,当iPad站在Smart Cover上时,应用程序看起来很不错(左图)。
要让iPad拨打application(_:supportedInterfaceOrientationsFor)
,请在Info.plist中保留iPad的肖像。该应用程序将失去Slide Over + Split View功能。但是您可以在一个地方锁定或解锁任何视图控制器的方向,而无需修改ViewController类。
最后,当显示/删除视图时,在视图控制器的生命周期中调用此函数。如果您的应用需要在其他时间锁定/解锁/更改方向,则可能无效
答案 10 :(得分:1)
使用
创建新扩展程序import UIKit
extension UINavigationController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
}
extension UITabBarController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
}
答案 11 :(得分:0)
感谢@ bmjohn的回答。这是一个有效的 Xamarin / C#版本的答案代码,以节省其他人的转录时间:
<强> AppDelegate.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);
}
答案 12 :(得分:0)
为此目的经过实际测试的解决方案。在我的示例中,我需要整个应用程序都处于纵向模式,但只有一个屏幕的方向应处于横向模式。
如上所述的AppDelegate中的代码描述了答案。
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)
}
然后在实际的viewcontroller(用于横向视图)中写下此代码
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.landscape, andRotateTo: UIInterfaceOrientation.landscape)
}
答案 13 :(得分:0)
这是一种适用于我的Swift 4.2(iOS 12.2)的简单方法,将其放在您要禁用shouldAutorotate的UIViewController
中:
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
.portrait
部分告诉它要保留的方向,您可以根据需要进行更改。选项包括:.portrait
,.all
,.allButUpsideDown
,.landscape
,.landscapeLeft
,.landscapeRight
,.portraitUpsideDown
。
答案 14 :(得分:0)
我做了一些实验,设法找到了解决此问题的解决方案。 该方法基于通过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;
}
最后在AppDelegate.swift中,检查当前显示的视图是否是我们标记的视图:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask
{
if (window?.viewWithTag(DesignerController.ViewTag)) != nil {
return .portrait;
}
return .all;
}
这种方法已经在我的模拟器上进行了测试,似乎效果很好。
注意:如果当前MVC与导航堆栈中的某些子级ViewController重叠,也会找到标记的视图。
答案 15 :(得分:0)
锁定和更改人像和风景方向的最佳解决方案:
在YouTube上观看此视频:
https://m.youtube.com/watch?v=4vRrHdBowyo
本教程是最佳和简单的。
或使用以下代码:
// 1-在第二个视图控制器中,我们设置了landscapeleft,在第一个视图控制器中,我们设置了portrat:
// 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
}
}