【问题标题】:how to lock portrait orientation for only main view using swift如何使用swift锁定仅主视图的纵向方向
【发布时间】:2014-09-01 12:59:19
【问题描述】:

我使用 swift 为 iPhone 创建了一个应用程序,它由嵌入在导航控制器中的许多视图组成。我想将主视图锁定为纵向,并且只有导航控制器的子视图锁定为横向。 这是我的意思的一个例子:

  • UINavigationController
    • UiViewController1(纵向锁定)带有按钮的初始视图控制器放置在导航栏上,使用户可以访问可以选择其他视图的列表
    • UIViewController2(锁定在横向)
    • UiViewController3(纵向和横向)
    • UiViewController4(纵向和横向)
    • ...
    • ...

我该怎么做?

【问题讨论】:

标签: ios swift


【解决方案1】:

根据Swift Apple DocssupportedInterfaceOrientations

讨论

当用户更改设备方向时,系统会在根视图控制器或填充窗口的最顶部呈现的视图控制器上调用此方法。如果视图控制器支持新方向,则窗口和视图控制器将旋转到新方向。仅当视图控制器的 shouldAutorotate 方法返回 true 时才会调用此方法。

您的导航控制器应覆盖shouldAutorotatesupportedInterfaceOrientations,如下所示。为了方便,我在UINavigationController 扩展中做到了这一点:

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

    public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        return (visibleViewController?.supportedInterfaceOrientations())!
    }
}

你的主视图控制器(一直是纵向的)应该有:

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.Portrait
}

然后,在您想要支持纵向或横向的子视图控制器中:

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.All
}

编辑:已针对 iOS 9 更新 :-)

【讨论】:

  • 当视图嵌入导航控制器时,我遇到了一个问题,例如,如果我想要两个视图,第一个是纵向的,第二个是横向的,则代码不起作用,在相同的导航控制器。
  • 请注意:在最新的 Swift 中,toRaw() 已被替换为 rawValue
  • 正如 Regis 上面所说的:新的函数签名需要 UIInterfaceOrientationMask 的返回值。这意味着现在正确答案是:override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return UIInterfaceOrientationMask.Portrait }
  • 我认为它在 iOS9 中不起作用。你能确认一下吗?
  • Swift 3 将这些从 func 更改为 var getter。只需将 func 更改为 var
【解决方案2】:

还回复了[here]

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

这个实现将它放在各个视图控制器上,以便在它们想要锁定方向时进行设置,而不是依靠 App Delegate 通过迭代子视图或依赖继承来找到它们。

斯威夫特 3

在 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
}

在其他一些全局结构或辅助类中,我在这里创建了 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")
    }

}

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

 override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(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)
}

【讨论】:

  • 请不要在多个问题中添加the same answer。回答最好的一个并将其余的标记为重复。见Is it acceptable to add a duplicate answer to several questions?
  • 这是我可以轻松发现的最佳答案。只有在 Swift 3 中对我有用的答案。
  • 其他答案对于最新开发者来说都是浪费时间。
  • @NileshPol 我让它在 iPad 和 iPhone 应用程序中工作。您可能想确保 plist 中支持的所有方向,以及在调试时调用的方法是否与您期望的一样?
  • @NileshPol 转到目标 => 常规并选中“需要全屏”它应该可以工作
【解决方案3】:

如果您的视图嵌入在故事板的 navigationcontroller 中,请设置导航控制器委托 UINavigationControllerDelegate 并添加以下方法

class ViewController: UIViewController, UINavigationControllerDelegate {
    func navigationControllerSupportedInterfaceOrientations(navigationController: UINavigationController) -> UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.Portrait
    }
}

【讨论】:

    【解决方案4】:

    更新:如果您在应用程序启动后在 iOS 10 中设置方向时遇到问题,请尝试在 ObjC 而不是 Swift 中进行设置,并使用 class MyNavigationController: MyNavigationControllerBase

    @implementation ABNavigationControllerBase
    - (NSUInteger)supportedInterfaceOrientations
    {
        return UIInterfaceOrientationMaskPortrait;
    }
    @end
    

    斯威夫特 3:

    class MyNavigationController: UINavigationController {
        override func viewDidLoad() {
            super.viewDidLoad()
            UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
        }
        override var shouldAutorotate: Bool {
            return false
        }
        override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
            return .portrait
        }
        override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
            return .portrait
        }
    }
    

    【讨论】:

    • 唯一对我有用的 Swift 3 / iOS 10 解决方案。谢谢!
    【解决方案5】:

    Swift 4.2+ 中的 JasonJasonJason 答案相同(它在 iOS 11 中正常工作)

    1- 覆盖 shouldAutorotate 和 supportedInterfaceOrientations,如下所示。

    extension UINavigationController {
    
    open override var shouldAutorotate: Bool {
        return true
    }
    
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return (visibleViewController?.supportedInterfaceOrientations)!
        }
    }
    

    2- 您的主视图控制器(始终为纵向)应该:

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

    3- 然后,在您想要支持纵向或横向的子视图控制器中:

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

    【讨论】:

      【解决方案6】:

      重要的想法是在 AppDelegate 中描述整个应用程序支持的界面方向。例如,要阻止所有视图显示纵向,只需执行以下操作:

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

      很多人只是通过谷歌搜索这个问题来寻找这个答案,所以我希望你能原谅我。

      在 Swift 3.0 中工作

      【讨论】:

      • 效果很好!谢谢
      【解决方案7】:

      在你想要人像的主控制器中,

      - (void)viewWillAppear:(BOOL)animated
      {
          [super viewWillAppear:animated];
      
      self.orientation = UIInterfaceOrientationMaskPortrait;
      //Or self.orientation = UIInterfaceOrientationPortraitUpsideDown
      }
      

      在你想要横向使用的 subVC 中

        self.orientation =  UIInterfaceOrientationLandscapeLeft:
         self.orientation =  UIInterfaceOrientationLandscapeRight:
      

      或者你可以覆盖这个方法

      - (NSUInteger)supportedInterfaceOrientations
      {
        return UIInterfaceOrientationMaskPortrait;
      } 
      

      这就是我在 iOS7 中使用 Obj-c 的方式,我认为这段代码也可以在 iOS8 中使用

      【讨论】:

      • 我无法访问 self.orientation
      • 我在写这个 sn-p 时考虑到了 ios7,如果你用 swift 编写代码,肯定有与此等价的东西。如果是这种情况,请查看 Apple 文档。
      • 我能理解你的问题,但是swift只是Obj-c的一个包装类,通过这个obj-c sn-p的等效swift代码,尝试搜索,swift文档中的屏幕方向
      【解决方案8】:

      为 swift2.0 编辑:

      override func shouldAutorotate() -> Bool {
              return false
      }
      
      override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
          return [.Portrait, .PortraitUpsideDown]
      }
      

      【讨论】:

      • Swift 4 使用 - 覆盖 var supportedInterfaceOrientations : UIInterfaceOrientationMask
      【解决方案9】:

      这里是 Swift 更新:-

      override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
          return UIInterfaceOrientationMask.Portrait
      }
      

      【讨论】:

      • 您能对此添加一些解释吗?地点、时间、方式等?
      • Swift 4 使用 - 覆盖 var supportedInterfaceOrientations : UIInterfaceOrientationMask
      【解决方案10】:

      这是 Swift 3 (XCode 8.2 beta) 的语法,其中这些方法转换为属性:

      extension UINavigationController {
          override open var shouldAutorotate: Bool {
              return false
          }
      }
      
      class ViewController: UIViewController {
      
          /*
                  ...
          */
      
          override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
              return UIInterfaceOrientationMask.portrait
          }
      }
      

      【讨论】:

      • 这会将所有屏幕锁定为纵向。如何仅锁定 1 个屏幕或仅锁定特定屏幕?
      • 您是否尝试过为每个单独的 ViewController 重写此方法(您可以使用多个)。
      • 没有。我要问的是上述解决方案如何仅适用于 1 个单屏?
      • 这就是我要回答的问题:每个屏幕都可以有一个视图控制器,因此请尝试(我没有尝试过)在您的应用程序的每个视图控制器上以不同的方式重载supportedInterfaceOrientations。如果它不起作用,您也可以发布一个新问题。
      【解决方案11】:

      这需要两件事

      • 通知控制器它支持旋转。
      • 强制执行轮换,然后将责任移交给知道其支持轮换的控制器。

      在视图控制器上声明一个强制方向为纵向的扩展。

      extension UIViewController {
      
        func forcePortrait() {
          UIView.setAnimationsEnabled(false)
          UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
          UIView.setAnimationsEnabled(true)
        }
      
      }
      

      任何锁定为纵向的视图控制器都可以继承特征。

      class PortraitViewController: UIViewController {
      
        override open var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait }
        override open var shouldAutorotate: Bool { return false }
      
        override func viewDidAppear(_ animated: Bool) {
          super.viewDidAppear(animated)
          forcePortrait()
        }
      
      }
      

      任何能够在纵向和横向之间旋转的视图控制器都可以继承这些特征。

      class LandscapeViewController: UIViewController {
      
        override open var supportedInterfaceOrientations: UIInterfaceOrientationMask { return [.landscape, .portrait]  }
        override open var shouldAutorotate: Bool { return true }
      
        override func viewWillDisappear(_ animated: Bool) {
          super.viewWillDisappear(animated)
          // if leaving for a portrait only screen, force portrait.
          // forcePortrait()
        }
      
      }
      

      如果您的横向视图控制器即将切换到纵向锁定屏幕。一定要在离开前锁定方向。然后依靠纵向视图控制器来强制自己缺乏旋转。

      【讨论】:

        【解决方案12】:

        这是锁定方向的工作代码:

        override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
            if UIDevice.current.userInterfaceIdiom == .phone {
                return .allButUpsideDown
            } else {
                return .all
            }
        }
        

        更多信息:

        https://www.hackingwithswift.com/example-code/uikit/how-to-lock-a-view-controllers-orientation-using-supportedinterfaceorientations

        【讨论】:

          【解决方案13】:

          您必须将此应用到您的顶视图控制器。但是,您可以通过子类化您的顶视图控制器并在其中设置一个变量以在每次调用时引用:

          shouldAutoRotate()
          

          当设备检测到方向变化并在调用之前调用:

          supportedInterfaceOrientations()//this is only called if shouldAutoRotate() returns true
          

          例如,假设我的顶视图控制器是 TabBarController:

          class SomeSubclassTabBarViewController: UITabBarController { //This subclass allows us to pass along data to each of the tabBars
          
          var dataArray = StoredValues()//also useful for passing info between tabs
          var shouldRotate: Bool = false
          
          
          override func shouldAutorotate() -> Bool { //allow the subviews accessing the tabBarController to set whether they should rotate or not
              return self.shouldRotate
          }
          

          }

          然后在应该能够旋转屏幕的视图中,像这样设置 viewWillAppear() 和 viewWillDisappear():

          override func viewWillAppear(animated: Bool) { //set the rotate capability to true
              let sharedTabBarController = self.tabBarController as SomeSubclassTabBarViewController
              sharedTabBarController.shouldRotate = true
          }
          
          override func viewWillDisappear(animated: Bool) {
              let sharedTabBarController = self.tabBarController as SomeSubclassTabBarViewController
              sharedTabBarController.shouldRotate = false
          }
          

          如果您的应用在此屏幕上崩溃,最好在 viewWillLoad() 方法中为每个视图显式设置 shouldRotate: Bool 值。

          【讨论】:

            【解决方案14】:

            在iOS8中,如果你想锁定一些特定的ViewController,创建一个UINavigationController的扩展(在你使用的情况下):

            extension UINavigationController {
            public override func shouldAutorotate() -> Bool {
            if visibleViewController is YourViewController {
                return false
            }
            return true
            }}
            

            【讨论】:

              【解决方案15】:

              如果您的 iOS 应用程序仅处于横向模式,并且您想在应用程序的横向模式下使用相机,那么请尝试以下解决方案。

              第 1 步:

              在你的 appdelegate.m 类中

              -(UIInterfaceOrientationMask)application:(UIApplication *)application
              supportedInterfaceOrientationsForWindow:(UIWindow *)window
              {
                  if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
                      NSString *captionVal = [TMUtils getValueInUserDefault:@"CAPTION"];
                      if ([captionVal isEqualToString:@"Camera"]) {
                          return UIInterfaceOrientationMaskPortrait;
                      }else{
                          return UIInterfaceOrientationMaskLandscapeRight;
                      }
                  }else{
                      return UIInterfaceOrientationMaskAllButUpsideDown;
                  }
              }
              

              这里您可以将共享偏好值 CAPTION 作为 keyValue 对并存储值“Camera”。

              第 2 步: 现在在相机按钮 Action 中的 viewController.m 类中设置共享首选项值并打开将具有相机功能的新 ViewController。

              [TMUtils setValueInUserDefault:@"CAPTION" value:@"Camera"];

              第 3 步: 在 Camera 功能 viewController.m 类中设置带有 UIImageView 和后退按钮的故事板。

              现在在相机功能 viewController.m 的 ViewDidLoad 中设置

              - (void)viewDidLoad {
                  [super viewDidLoad];
              
                  if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
                          NSLog(@"Error");
                      } else {
              
                          UIImagePickerController *pickerController = [[UIImagePickerController alloc] init];
                          pickerController.modalPresentationStyle = UIModalPresentationCurrentContext; //this will allow the picker to be presented in landscape
                          pickerController.delegate = self;
                          pickerController.allowsEditing = YES;
                          pickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
                          [self presentViewController:pickerController animated:YES completion:nil];
                      }
              }
              

              现在在 UIImagePickerController 委托方法中将图像设置为 UIImageView

              - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
              
                      UIImage *chosenImage = info[UIImagePickerControllerOriginalImage];
                      self.cameraImage.image = chosenImage;
                      [picker dismissViewControllerAnimated:YES completion:NULL];
              }
              

              现在在相机背面 UIButton

              - (IBAction)cameraBtnAction:(id)sender {
                  [TMUtils setValueInUserDefault:@"CAPTION" value:@"NOCamera"];
                  [self dismissViewControllerAnimated:YES completion:nil];
              }
              

              它将始终根据委托类函数中的共享首选项值检查supportedInterfaceOrientationsForWindow 参考该值它允许相机功能ViewController以纵向模式打开相机并休息它将再次返回横向模式,这将完全正常工作.

              【讨论】:

                【解决方案16】:

                当 UIKit 检测到设备方向发生变化时,它使用UIApplication 对象和根视图控制器来确定是否允许新的方向。如果两个对象都同意支持新方向,则发生自动旋转。否则,忽略方向变化。

                默认情况下,UIApplication 对象从应用程序的信息属性列表中为 UISupportedInterfaceOrientations 键指定的值获取其支持的界面方向。您可以通过在应用程序的委托中实现 application:supportedInterfaceOrientationsForWindow: 方法来覆盖此行为。此方法返回的支持的方向值仅在应用程序启动完成后生效。因此,您可以使用此方法在启动后支持一组不同的方向。

                允许您的应用在启动后旋转为纵向。

                - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
                {
                    return UIInterfaceOrientationMaskAllButUpsideDown;
                }
                

                来源:https://developer.apple.com/

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多