iOS应用具有两个意义不同的“方向”,分别是设备方向(device orientation)和界面方向(interface orientation)。
设备方向指的是设备的物理方向,包括正的竖排方向(right-side up)、倒置方向(upside down)、左旋转方向(rotated left)、右旋转方向(rotated right)、正面朝上和背面朝上。可以通过UIDevice类的orientation属性获取设备方向。
而界面方向是指用户所看到的应用界面的方向。以下是所有可能的界面方向:
UIInterfaceOrientationPortrait竖排方向,主屏幕按钮位于屏幕下方
UIInterfaceOrientationPortraitUpsideDown竖排方向,主屏幕按钮位于屏幕上方
UIInterfaceOrientationLandscapeLeft横排方向,主屏幕按钮位于屏幕右侧
UIInterfaceOrientationLandscapeRight横排方向,主屏幕按钮位于屏幕左侧
当应用的界面方向发生变化时,UIWindow对象会根据新的界面方向调整自身大小并旋转其视图层次结构。同时,视图层次结构中的所有视图对象都会根据相关约束重新调整自身布局。
打开Homepwner.xcodeproj,在iPad模拟器上构建并运行应用。
当Homepwner在iPad模拟器上运行时,可以模拟转屏操作。选中某一个BNRItem对象,进入详细界面,然后在模拟器的Hardware菜单中选择Rotate Left。这时,模拟器窗口以及应用界面会向左旋转,由于事先已经为视图添加了约束,因此Homepwner在任何方向都可以很好地显示。
当设备方向发生改变时,应用会收到新的方向信息,并根据相关设置决定是否根据新的设备方向调整界面方向。
再次点击Rotate Left选项,此时模拟器会处于倒置方向,但是界面方向并没有随之改变——原因:Homepwner不支持将界面方向设置为UIInterfaceOrientationPortraitUpsideDown。第15章在项目属性页面将Homepwner改为通用应用,本章将在相同的页面修改Homepwner所支持的界面方向。
选择Target信息中的General标签项,在展开的Deployment Info中选择iPad,可以看见Device Orientation后面的四个选项中除第二行的Upside Down外,Portrait、Landscape Left和 Landscape Right 都已选中。请读者选中Upside Down(见图17-1)。
图17-1 修改Homepwner,支持Upside Down界面方向
构建并在iPad模拟器上运行应用,在Hardware菜单中将模拟器向同一个方向旋转两次。现在Homepwner可以支持倒置的界面方向了。通常,iPad应用需要支持所有界面方向,而iPhone应用需要支持除Upside Down以外的界面方向。在Deployment Info中选择iPhone,可以看到应用在iPhone或iPod Touch上不支持Upside Down。
有时可能需要使应用只支持某些特定的界面方向。例如,许多游戏应用只支持两个横排方向;许多iPhone应用只支持正的竖排方向。勾选或取消Device Orientation中的选项可以选择合适的界面方向。
实际上,不但可以设置应用的界面方向,还可以为应用中的每个UIViewController单独设置界面方向。(在Homepwner中,主要包括以模态形式显示的BNRDetaileViewController和其余包含在UINavigationController中的UIViewController。)每个UIViewController都可以在supportedInterfaceOrientations方法中返回自身支持的界面方向。当界面方向发生变化时,应用的rootViewController以及应用自身(应用的Info.plist中的Supported Interface Orientations部分)都必须支持新的界面方向,应用才能旋转至该方向。
默认情况下,UIViewController对象在iPad中支持所有界面方向,在iPhone中则支持除Upside Down以外的界面方向。如果需要修改默认支持方向,则必须在相应的UIViewController中覆盖supportedInterfaceOrientations方法,该方法的默认实现类似于以下代码:
- (NSUInteger)supportedInterfaceOrientations
{
if ([UIDevice currentDevice].userInterfaceIdiom
== UIUserInterfaceIdiomPad) {
return UIInterfaceOrientationMaskAll;
} else {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
}
以上代码会根据应用当前运行的设备改变支持的界面方向。首先通过UIDevice的类方法currentDevice获取表示当前设备的对象,然后根据该对象的userInterfaceIdiom属性判断当前运行的设备是iPad还是iPhone。截至本书写作期间,该属性的值可能是UIUserInterfaceIdiomPhone或UIUserInterfaceIdiomPad。最后根据设备类型决定应用支持的界面方向。
假设应用的根视图控制器只支持两个横排方向,则可以在supportedInterface- Orientations方法中添加以下代码:
- (NSUInteger)supportedInterfaceOrientations
{
// 对于所有设备,只支持左横排方向和右横排方向
return UIInterfaceOrientationMaskLandscapeLeft
| UIInterfaceOrientationMaskLandscapeRight;
}
(如果不了解按位或“|”运算符,可以参考本章17.8节)。
在许多应用中,UINavigationController和UITabViewController是出现频率最高的两种视图控制器。UINavigationController使用继承自UIViewController的supportedInterfaceOrientations。如果需要由UINavigationController当前显示的视图控制器来决定所支持的界面方向,则可以创建UINavigationController的子类并覆盖supportedInterfaceOrientations方法,代码如下:
@implementation MyNavigationController
- (NSUInteger)supportedInterfaceOrientations
{
return self.topViewController.supportedInterfaceOrientations;
}
@end
UITabViewController则会依次检查每个标签项所支持的界面方向,然后在自身的supportedInterfaceOrientations方法中返回所有标签项都支持的界面方向。