转载: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. 吐槽:基于PhoneGap开发移动项目

    目前,随着Google的Android手机和苹果的iphone手机的逐渐普及,越来越多开发者加入到移动应用开发的大军当中.其中,Android应用是基于Java语言基础上进行开发的,而苹果公司的iph ...

  2. css中的expression

    最近对CSS中的行为比较感兴趣,虽然是不符合标准的也只有ie才能识别,但是他确实给css的功能扩展了不少.下面是摘自互联网上的文字和例子,因为都被转烂了,没法注明出处. IE5及其以后版本支持在CSS ...

  3. .NET平台开源项目速览(7)关于NoSQL数据库LiteDB的分页查询解决过程

    在文章:这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧!(第二辑) 与 .NET平台开源项目速览(3)小巧轻量级NoSQL文件数据库LiteDB中,介绍了LiteDB的基本使用情况以及部 ...

  4. 追根溯源:EntityFramework 实体的状态变化

    阅读目录: 1. 应用场景 2. 场景测试 3. 问题分析 4. 追根溯源 5. 简要总结 1. 应用场景 首先,应用程序使用 EntityFramework,应用场景中有两个实体 S_Class(班 ...

  5. EntityFramework 7 Left Join Where is error(Test record)

    First of all, my English is very poor, so I may not be a very good expression, very sorry! In this b ...

  6. JavaScript中Promises/A+规范的实现

    Promises是一种异步编程模型,通过一组API来规范化异步操作,这样也能够让异步操作的流程控制更加容易. 下面的代码是假设执行一个异步队列,每一项都会使用上一项返回的数据: function ne ...

  7. Cesium原理篇:6 Renderer模块(2: Texture)

    Texture也是WebGL中重要的概念,使用起来也很简单.但有句话叫大道至简,如果真的想要用好纹理,里面的水其实也是很深的.下面我们来一探究竟. 下面是WebGL中创建一个纹理的最简过程: var ...

  8. 关于Java中的static关键字

    Java中的 static 关键字,确实是一个关键的字(key word),今天就来总结一下它的用法,说说为什么关键. Java中的 static 关键字主要是用来做内存管理的.理解了这句话才能够比较 ...

  9. (八)WebGIS中栅格图层的设计

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.    前言 我们在上一章里了解到WebGIS中栅格图层的本质—— ...

  10. Jackson的简单用法

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1简介 Jackson具有比较高的序列化和反序列化效率,据测试,无论是 ...