转载:http://blogread.cn/it/article/7765?f=wb#original

代码示例:https://github.com/johnlui/Swift-On-iOS/tree/master/ControlOrientation/ControlOrientation

环境要求:Xcode 7 / Swift2.0

前两天遇到了一个 “使用指定的不同屏幕方向打开新页面” 的需求,需求很简单:APP 一直保持竖屏,要求新打开的页面能够指定为横屏或竖屏,并且不允许自动切换,新页面退出后要恢复竖屏。

准备工作

新建一个单页面项目,命名为 ControlOrientation。接下来取消 Landscape Right 的勾选,我们的 APP 将只支持 竖屏(Portrait)和 Landscape Left:

以横屏打开新页面

给 Main.storyboard 拖入一个 View Controller,新建一个继承自 UIViewController 的类,名为 SecondViewController,然后将两者绑定。之后给新建的这个 View Controller 赋予 StoryBoard ID 值 “secondVC”:

简单 Google 便可以得到代码方式指定横屏打来新页面的方式:

在新页面的 viewDidLoad 中执行:

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

在启动页中间添加一个居中的按钮,拖动绑定点击事件,加入载入新页面的代码:

@IBAction func openNewVC(sender: AnyObject) {
if let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("secondVC") as? SecondViewController {
self.presentViewController(vc, animated: true, completion: nil)
}
}

运行!查看效果:

代码控制横屏成功!

还有一个收尾工作:给 SecondViewController 增加一个退出按钮,这一步就不再描述啦。然后再次运行项目,查看效果:

出来之后也变横屏了哎,这不是我们想要的。

屏幕方向锁定

重读文章开头的需求,我们就会发现需求要求我们在任何一个界面都不能因为手机物理方向的变化而自动改变屏幕方向,稍微 Google 一下,我们就会得到锁死屏幕方向的代码:

给 ViewController 和 SecondViewController 都增加一个函数:

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

为了直观的给大家展示,我们将通过手动改变模拟器的方向来模拟真机屏幕方向的变化(改变模拟器屏幕方向的快捷键是 Command 加左或者右),检验效果:

简直完美呀!是不是觉得有点太简单了?这么容易就实现了?当然不是,这么容易我还写个毛的文章呀。

神级 BUG

既然新打开横屏已经完美解决了,那么新打开竖屏怎么样呢?让我们把那一行切换屏幕方向的代码注释掉,运行查看结果:

BUG 了!!

解决 BUG

这个 bug 我搞了两天,虽然不是一直在搞它,但是总时长也至少有八个小时。其实严格意义上来讲,这并不是 bug,这只是我们不知道怎么才能搞定而已。最后我终于搞明白了这个 BUG 背后的运行原理,先说解决方案:

竖屏解决方案

在第一个页面 ViewController 中增加以下两个函数:

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

在第二个页面 SecondViewController 中增加两个函数:

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

查看效果:

竖屏搞定!

横屏解决方案

将 SecondViewController 中的函数改为:

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

别忘了打开 viewDidLoad 函数中的横屏控制代码哦。查看效果:

横屏搞定!

全搞定了吗?并没有

我们还是 Too Young Too Simple,在我们简陋的例子中,似乎确实已经全搞定了,但是实际工程中大多数项目都不是普通 View Controller 作为根控制器哦~

我们测试一下 QQ、微信、微博 等 APP 采用的通用方案:根控制器为 TabBarController,之后嵌套 NavigationController,然后放入 ViewController 页面进行展示,然后 present 出 SecondViewController。

搭 VIE TNV(TabbarController->NavigationController->ViewController) 架构

我们可不是跟风在国外上市的中国互联网公司拆 VIE 架构哦~

  • 选中 ViewController,点击菜单中的 Editor -> Embed In -> Navigation Controller,第一层嵌套完成。

  • 选中 NavigationController,点击菜单中的 Editor -> Embed In -> Tab Bar Controller,第二层嵌套完成。

如图:

查看效果:

这他妈什么玩意儿 o(╯□╰)o

终极解决方案

我埋坑的过程就不细说了,下面直接给出特性分析及解决方案:

特性分析

跟 shouldAutorotate() 不同,判断是否应该改变 APP 屏幕方向并不会检测当前显示的 View Controller 的属性,而是去检测根 View Controller 的属性,所以我们要从 TabBarController 一路获取到当前 View Controller。

解决方案

新建一个继承于 UITabBarController 的类,名为 TabBarController,将其和 StoryBoard 中的 Tab Bar Controller 页面绑定。该类完整代码如下:

import UIKit

class TabBarController: UITabBarController, UITabBarControllerDelegate {

    override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
} override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
} override func shouldAutorotate() -> Bool {
return false
}
func tabBarControllerSupportedInterfaceOrientations(tabBarController: UITabBarController) -> UIInterfaceOrientationMask {
return self.selectedViewController!.supportedInterfaceOrientations()
}
func tabBarControllerPreferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
return self.selectedViewController!.preferredInterfaceOrientationForPresentation()
}
}

同样,新建一个继承于 UINavigationController 的类,名为 NavigationController,将其和 StoryBoard 中的 Navigation Controller 页面绑定。向该类添加以下代码:

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return self.visibleViewController!.supportedInterfaceOrientations()
}
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
return self.visibleViewController!.preferredInterfaceOrientationForPresentation()
}

检查结果

写在最后

通过本文我们可以总结出以下两点:

  • 是否自动转换屏幕方向由当前显示的 View Controller 决定。

  • 是否支持横屏和是否优先选择横屏由 rootViewController 决定,若有多层结构嵌套,则需要层层专递,将控制权交给当前显示的页面。类似于 代理传值 和 延迟静态绑定。

另外,我利用 Swift 的 enum 给 SecondViewController 类加上了一个优雅的 横屏/竖屏 控制开关,具体代码可以在 Github 上查看。

iOS如何用代码控制以不同屏幕方向打开新页面?的更多相关文章

  1. HBuilder mui 手机app开发 Android手机app开发 ios手机app开发 打开新页面 预加载页面 关闭页面

    创建子页面 在mobile app开发过程中,经常遇到卡头卡尾的页面,此时若使用局部滚动,在android手机上会出现滚动不流畅的问题: mui的解决思路是:将需要滚动的区域通过单独的webview实 ...

  2. 【iOS 开发】iOS 开发 简介 (IOS项目文件 | MVC 模式 | 事件响应机制 | Storyboard 控制界面 | 代码控制界面 | Retina 屏幕图片适配)

    一. iOS 项目简介 1. iOS 文件简介 创建一个 HelloWorld 项目, 在这个 IOS 项目中有四个目录 : 如下图; -- HelloWorldTests 目录 : 单元测试相关的类 ...

  3. 控制使用jquery load()方法载入新页面中的元素

    最近在项目中用到jquery的load()方法来加载页面,首先简单说一下load()方法. load(url,data,callback);该方法接收三个参数,第一个是载入的页面地址,第二个是要传到服 ...

  4. java:如何用代码控制H2 Database启动

    1.纯手动start/stop package com.cnblogs.yjmyzz.h2; import java.sql.Connection; import java.sql.DriverMan ...

  5. iOS 屏幕方向

    参考文章:http://www.tuicool.com/articles/e2q6zi 一般的应用,只会支持竖屏正方向一个方向,支持多个屏幕方向的应用还是比较少的. 当时也没搞明白,所以直接就设置了正 ...

  6. 游戏开发之在UE4中编写C++代码控制角色

    当你运行我们上次做完的项目,你可能会意识到我们移动的摄像机还是默认的那个摄像机,这个默认的摄像机可以自由飞翔.这一节,我们要使得开始的角色是我们的一个Avatar类的实例对象,并且使用键盘控制我们的角 ...

  7. iOS开发通过代码方式使用AutoLayout (NSLayoutConstraint + Masonry)

    iOS开发通过代码方式使用AutoLayout (NSLayoutConstraint + Masonry) 随着iPhone6/6+设备的上市,如何让手头上的APP适配多种机型多种屏幕尺寸变得尤为迫 ...

  8. 谈谈iOS中的屏幕方向

    众所周知,iOS中提供了[UIDevice currentDevice].orientation与[UIApplication sharedApplication].statusBarOrientat ...

  9. 可控制导航下拉方向的jQuery下拉菜单代码

    效果:http://hovertree.com/texiao/nav/1/ 代码如下: <!DOCTYPE html> <html> <head> <meta ...

随机推荐

  1. 一个美术需求引发的Custom Inspector

    需求 Editor模式下,在运行或者非运行状态下,能够按照指定的变化率来自动改变material中属性数值. 需求分析 如何在Editor模式下获得一个游戏对象及其组件,尤其是在非运行状态下?我们知道 ...

  2. c++头文件 #include<iostream>

    cout<<"C1="<<setiosflags(ios::fixed)<<setprecision(2)<<3.14*r*2< ...

  3. Qt on Android:创建可伸缩界面

    使用 Qt 来开发 Android 应用,也需要适配不同移动设备,适配多种多样的屏幕和分辨率.这次我们大概来讲一下如何使用 Qt 提供的机制来创建可伸缩的界面. DPI 必须要解释一下 DPI . D ...

  4. Visualize Surface by Delaunay Triangulator

    Visualize Surface by Delaunay Triangulator eryar@163.com Abstract. Delaunay Triangulation is the cor ...

  5. 从零开始编写自己的C#框架(4)——文档编写说明

    在写本系列的过程中,了解得越多越不知道从哪里做为切入点来写,几乎每个知识点展开来说都可以写成一本书.而自己在写作与文档编写方面来说,还是一个初鸟级别,所以只能从大方面说说,在本框架开发所需的范围内来讲 ...

  6. setTimeout与取号机之间的关系

    说到setTimeout写过javascript的伙伴们一定不会陌生,去银行办过存取款业务的伙伴一定对取号机不会陌生.今天群里有个好伙伴在问setTimeout的问题,大伙你一言我一语,讲了很多,可是 ...

  7. MyCAT简易入门

    MyCAT是mysql中间件,前身是阿里大名鼎鼎的Cobar,Cobar在开源了一段时间后,不了了之.于是MyCAT扛起了这面大旗,在大数据时代,其重要性愈发彰显.这篇文章主要是MyCAT的入门部署. ...

  8. 构建自己的PHP框架--实现Model类(1)

    在之前的博客中,我们定义了ORM的接口,以及决定了使用PDO去实现.最后我们提到会有一个Model类实现ModelInterface接口. 现在我们来实现这个接口,如下: <?php names ...

  9. C#动态调用WCF接口,两种方式任你选。

    写在前面 接触WCF还是它在最初诞生之处,一个分布式应用的巨作. 从开始接触到现在断断续续,真正使用的项目少之又少,更谈不上深入WCF内部实现机制和原理去研究,最近自己做一个项目时用到了WCF. 从这 ...

  10. 关于Javascript作用域及作用域链的总结

    本文是根据以下文章以及<Javascript高级程序设计(第三版)>第四章相关内容总结的. 1.Javascript作用域原理,地址:http://www.laruence.com/200 ...