小试iOS设备上屏幕的旋转
说起来真是惭愧呢,明明是一个超级基本的问题,但是我竟然现在才尝试去接触它,因为之前做的几个app,都是不支持屏幕旋转的啊(可怜脸)
不过没关系啦,小试一下就又涨了一个姿势。
顺便,从现在开始,我要用Swift来写代码片段了。以及这里写的内容都是针对iOS6以后的。
设备的旋转方向和屏幕的旋转方向
觉得最重要的事情,就是知道Device Orientation(设备的旋转方向)和Interface Orientation(屏幕的旋转方向)是两个不同的概念。前者只是代表了设备的一种状态,而后者是屏幕为了应对不同的设备状态,做出的用户界面上的回应。
设备的旋转方向
Device Orientation表示的是这个iOS设备的旋转方向。除了Unknown之外,它有6个值(每个维度两个方向),定义在UIDevice这个类中:
enum UIDeviceOrientation : Int {
case Unknown
case Portrait // Device oriented vertically, home button on the bottom
case PortraitUpsideDown // Device oriented vertically, home button on the top
case LandscapeLeft // Device oriented horizontally, home button on the right
case LandscapeRight // Device oriented horizontally, home button on the left
case FaceUp // Device oriented flat, face up
case FaceDown // Device oriented flat, face down
}
既然是定义在UIDevice中的,也就是说明,Device Orientation是设备的一种状态,与当前运行着哪个app没有什么关系,与屏幕也没有什么关系。
每当设备被旋转的时候,系统会发送UIDeviceOrientationDidChangeNotification
通知,让有需要的app得知设备旋转的消息。使用以下代码就可以查询设备当前的旋转方向了:
println("Device Orientation \(UIDevice.currentDevice().orientation.rawValue)")
无论运行着的app的屏幕会不会旋转,只要整个设备旋转,它就会收到这个通知。
不过,在iOS的控制中心,可以关闭设备旋转的开关。这个开关关闭后,app将不能正确的收到UIDeviceOrientationDidChangeNotification
通知(app启动的时候可以收到一次,但是之后旋转设备,这个通知就不能被收到了)。
屏幕的旋转方向
Interface Orientation代表的则是用户界面的旋转方向。比如iOS8的照片应用,在设备旋转时,其中view的布局也会跟着变化。
除了Unknown,Interface Orientation有4个值:
enum UIInterfaceOrientation : Int {
case Unknown
case Portrait
case PortraitUpsideDown
case LandscapeLeft
case LandscapeRight
}
可以发现,它没有与UIDeviceOrientation中的FaceUp和FaceDown对应的值,对啊,当手机面朝上或者面朝下的时候,用户界面如果要变化,那应该是一件很奇怪的事情。
另外,UIInterfaceOrientation
中的LandscapeLeft
等价于UIDeviceOrientation
中的LandscapeRight
,反之亦然。那是因为,当设备向右旋转时,用户界面中的内容应该是向左旋转,才能呈现正确的方向。
通过查询
UIApplication.sharedApplication().statusBarOrientation
可以获取状态栏的方向,也就是当前用户界面的方向。
并不是所有的app都会对设备旋转做出用户界面上对应的旋转。所以,程序员也不能通过查询设备的当前方向,来推断用户界面的方向;也不能通过查询用户界面的方向,来推断设备的方向。Device Orientation和Interface Orientation是两个不同的概念。
在一个app中,可以直接指定整个app支持的旋转方向;也可以对每个容器controller指定其支持的旋转方向:
App层面的屏幕旋转
可以在Xcode project的general这个标签下,设置app支持的屏幕旋转方向。
也可以在info.plist文件中设置Supported interface orientations。
设置plist文件
容器controller层面的旋转
在view controller中,可以通过重写supportedInterfaceOrientations
方法指定支持的旋转方向:
override func supportedInterfaceOrientations() -> Int {
return UIInterfaceOrientation.Portrait.rawValue
}
也可以通过重写shouldAutorotate
方法,判断每次可能旋转是否应该完成:
override func shouldAutorotate() -> Bool {
return true
}
只有已经被支持的旋转方向才会调用shouldAutorotate
这个方法。也就是说,这个view controller真正支持的旋转方向,是supportedInterfaceOrientations
中指定的方向和shouldAutorotate
中返回为true的情况的相与。
在一个app的每个view controller中,可以分别指定当前view controller支持的旋转方向。但是这里所指的view controller,必须是root view controller或者全屏的view controller,不然相关方法是不会被调用的。
所以说,如果这个view controller是被包含在navigation controller或者tab bar controller中的时候,被包含的view controller的supportedInterfaceOrientation
方法是不会被调用的。这时需要程序员自己来handle这个情况。
参考
Supporting Multiple Interface Orientations
iOS的横屏(Landscape)与竖屏(Portrait)InterfaceOrientation
iOS6的旋屏控制技巧