我使用 swift 为iPhone创建了一个应用程序,该应用程序由嵌入在导航控制器中的许多视图组成。我想将主视图锁定为纵向方向,并且仅锁定横向方向的导航控制器的子视图。 这是我的意思的一个例子:
我该怎么做?
答案 0 :(得分:49)
根据supportedInterfaceOrientations
的{{3}}:
讨论
当用户更改设备方向时,系统会在根视图控制器或填充窗口的最顶层显示的视图控制器上调用此方法。如果视图控制器支持新方向,则窗口和视图控制器将旋转到新方向。仅当视图控制器的shouldAutorotate方法返回true时才调用此方法。
您的导航控制器应覆盖shouldAutorotate
和supportedInterfaceOrientations
,如下所示。为了方便起见,我在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更新: - )
答案 1 :(得分:17)
还回答了[here]
当您拥有复杂的视图层次结构时,例如拥有多个导航控制器和/或制表视图控制器,事情会变得非常混乱。
此实现将它放在各个视图控制器上,以设置何时锁定方向,而不是依靠App Delegate通过迭代子视图或依赖继承来查找它们。
Swift 3
在AppDelegate中:
Iceland
在其他一些全局struct或helper类中,我在这里创建了AppUtility:
/// 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
}
然后在想要的ViewController中锁定方向:
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")
}
}
答案 2 :(得分:6)
更新:如果您在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
}
}
答案 3 :(得分:5)
同样 JasonJasonJason 回答 Swift 4.2 + (它与 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
}
答案 4 :(得分:3)
重要的想法是在AppDelegate中描述整个应用程序支持的界面方向。例如,要将所有视图阻止为纵向,只需执行以下操作:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask{
return UIInterfaceOrientationMask.portrait
}
很多人都在寻找这个答案谷歌搜索这个问题所以我希望你能原谅我。
适用于Swift 3.0
答案 5 :(得分:2)
在你想要肖像的主控制器中,
- (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
答案 6 :(得分:1)
这是Swift更新: -
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.Portrait
}
答案 7 :(得分:1)
为swift2.0编辑:
override func shouldAutorotate() -> Bool {
return false
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return [.Portrait, .PortraitUpsideDown]
}
答案 8 :(得分:1)
这是Swift 3(XCode 8.2 beta)的语法,其中这些方法转换为属性:
class table_name extends Model
{
//
}
答案 9 :(得分:1)
这需要两件事
在视图控制器上声明一个扩展,以强制将方向设置为纵向。
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()
}
}
如果您的风景视图控制器即将锁定到人像锁定屏幕。确保在离开前锁定方向。然后依靠人像视图控制器来强制自己缺乏旋转。
答案 10 :(得分:1)
以下是用于锁定方向的工作代码:
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
更多信息:
答案 11 :(得分:0)
您必须将此应用于顶级视图控制器。但是,您可以通过子类化顶级视图控制器并在其中设置一个变量来以干净/简单的方式执行此操作,以便在每次调用时引用:
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值可能是个好主意。
答案 12 :(得分:0)
在iOS8中,如果要锁定某些特定的ViewController,请创建UINavigationController的扩展(在您使用它的情况下):
extension UINavigationController {
public override func shouldAutorotate() -> Bool {
if visibleViewController is YourViewController {
return false
}
return true
}}
答案 13 :(得分:0)
如果您的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: 现在,在“相机”按钮“动作”的viewController.m类中,设置共享的首选项值并打开将具有相机功能的新ViewController。
[TMUtils setValueInUserDefault:@“ CAPTION”值:@“ Camera”];
步骤3: 在“相机”功能的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];
}
它始终会根据委托类函数中的sharedInterface值检查所支持的InterfaceOrientationsForWindow的值,并参考该值允许相机功能ViewController在纵向模式下打开相机,然后再次返回横向模式,这将完全正常
答案 14 :(得分:0)
当UIKit检测到设备方向发生变化时,它将使用UIApplication
对象和根视图控制器来确定是否允许新的方向。如果两个对象都同意支持新方向,则将发生自动旋转。否则,方向更改将被忽略。
默认情况下,UIApplication
对象从应用程序的“信息属性列表”中为UISupportedInterfaceOrientations
键指定的值中获取其支持的界面方向。您可以通过在应用程序的委托中实现application:supportedInterfaceOrientationsForWindow:
方法来覆盖此行为。此方法返回的受支持的方向值仅在应用程序启动完成后生效。因此,您可以在启动后使用此方法来支持一组不同的方向。
允许您的应用在启动后旋转为纵向。
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}