iOS_book03 -自动旋转、自动调整大小、尺寸分类器
自动旋转(autorotation):支持在纵向模式(长而窄)或横向模式(短而宽)下使用应用程序,支持在旋转设备时更改应用程序的方向。
苹果公司建议iPad上的大部分应用程序都应该支持所有的方向。
对于iPhone应用,基本原则是:如果自动旋转能够增强用户体验,就应该将它们添加到应用中。对于iPad应用,添加自动旋转功能是一项铁则。
注意:如果应用程序显示了状态栏,则垂直屏幕上程序实际可用的空间将在垂直方向上减少20点。状态栏位于屏幕顶部,高度为20点,用于显示信号强度、时间以及电池电量等信息。
点、像素和Retina显示屏
Retina显示屏是苹果公司的销售术语,指的是iPhone4后续的所有iPhone型号、后几代iPod touch和最新几款iPad使用的高分辨率屏幕。
在操作屏幕上的界面元素时,使用点而非像素来指定其尺寸和距离。对于早期的iPhone(以及iPad、iPad2和iPad mini1)来说,点和像素是等价的,一个点就是一个像素。然而,在较新的iPhone、iPad和iPod touch上,1点相当于4像素的面积(宽和高都是2像素)。比如iPhone5s屏幕宽度实际上是640像素,但是依然表现为320点。而在iPhone6Plus中,缩放比例是3.因此每个点对应9像素的正方形。
鉴于iOS自动把点映射到屏幕的物理像素,可以把点看做“虚拟分辨率”(virtual resolution)。
为了应对设备的旋转,需要为界面中的所有对象指定合适的约束。调整视图时,约束可以告诉iOS设备应该如何对控件进行调整。
可以把约束理解为描述视图几何属性的方程式,而iOS视图系统就是求解程序,在必要时对视图进行调整,使其满足方程式所描述的几何属性。
有两种方式可以设置iOS视图支持界面旋转:
一种是创建一个应用级的设置(这会成为所有视图控制器的默认支持方向), 也可以为每个独立的试图控制器作进一步调整。
应用级支持的方向:
在项目设置中的General界面中,可以看到一部分标题为Deployment info, 其中包含一组名为Device Orientation的复选框,这就是指定应用程序支持方向的方法。
这并不意味着应用中的每一个视图都要支持被选中的方向,但如果想让所有的应用程序视图都支持某个方向,就必须在这里选中该方向。
默认情况下Upside Down方向(Home键位于上方)是不被选中的,这是因为,如果在iPhone倒置时来电,那么在接听电话时,手机不可能仍然处于倒置状态。
Device Orientation复选框实际上只是一种在应用的info.plist文件中添加、删除相关项的便捷方式。
独立控制器的选转支持。
对视图控制器进行配置,使它支持不同的方向(应用级支付方向的子集),
注意:我们在应用的全局配置中指定应用所支持方向的绝对上限。如果全局配置不支持Upside Down方向,那么任何一个视图控制器都不能迫使系统选转到Upside Down方向。在视图控制器能做的,就是在可接受的范围内做进一步限制。
在父类UIViewController中定义方法,这个方法可以指定当前视图控制器所支持的方向:
Swift:
override fun supportedInterfaceOrientations -> Int {
return Int(UIInterfaceOrientationMsk.Portrait.rawValue) | Int(UIInterfaceOrientationMask.LandscapeLeft.rawValue)
}
Objective-C
- (NSUInteger)supportedInterfaceOrientations {
return (UIInterfaceOrientationMaskPortrait
return (UIInterfaceOrientationMaskPortrait
| UIInterfaceOrientationMaskLandscapeLeft);
}
这个方法使用C语言风格的掩码返回所有支持的方向。这就是iOS询问一个视图控制器是否支持旋转到某个指定方向的方法。
在这个方法中,返回值表示可以接受两种方向:默认的纵向方向和顺时针旋转90度之后的横向(也就是手机左侧边缘位于上方时的方向。)使用OR操作符把两个方向掩码组合在一起作为返回值。
UIKit定义了如下的方向掩码(以Swift为例),可以使用OR操作符任意组合这些掩码。
UIInterfaceOrientationMask.Portrait
UIInterfaceOrientationMask.LandscapeLeft
UIInterfaceOrientationMask.LandscapeRight
UIInterfaceOrientationMask.PortraitUpsideDown
除此之外,还有几个预定义的通用组合值,直接使用这些组合值与使用OR操作符完全等价:
UIInterfaceOrientationMask.Landscape
UIInterfaceOrientationMask.All
UIInterfaceOrientationMask.AllButUpsideDown
当iOS设备旋转到一个新的方向时,supportedInterfaceOrientations方法就会在当前活动的视图控制器上被调用。如果这个方法的返回值中包含新的方向,那么应用程序就会旋转当前视图,否则不旋转。
因为每个视图控制器子类都可以覆盖这个方法,所以:对于应用程序来说,可以让某些视图支持旋转,而另外的视图不支持;对于单个视图控制器来说,可以在特定条件下支持特定的方向。
iOS实际上有两种不同类型的方向。这里讨论的是界面方向(interface orientation)。另一个独立但相关的概念是设备方向(device orientation)。设备方向表示设备当前的持握方式,而界面方向则是指屏幕上视图的旋转方向。如果把iPhone上下颠倒过来,那么设备方法就是倒置的,但是界面方向却只能是其他的三个方向之一,因为iPhone应用默认不支持Upside Down方向。
通过Editor>Resolve Auto Layout Issues > Add Missing Constraints选项为上下左右角的标签添加约束。
然后可以看到,有一些紧挨着标签的蓝色实线。每条蓝色实线代表一个约束。
按下Option+Command+5来打开尺寸检查器(Size Inspector),可以看到里面有包含约束的列表。
在上图标签中,其中两个约束负责处理当前标签位置与父视图(即容器视图)之间的关系:
它指定了前置空白(leading space, 通常意味着到左边的间距)和
底部空白(bottom space, 即标签下面的空间)。
父视图的尺寸发生变化时(比如设备旋转), 这些约束会使标签与父视图顶部和左边的间距不变。
Pin>Horizontal Spacing选项,这个约束会告诉布局系统,让这些标签之间始终保持与当前一样的水平间距。
确保一个标签处于选中状态,按住Shift键并且单击另一个标签。这样就同时选中了这两个标签,然后就可以创建一个对这两个标签都起作用的约束。
如果错误的添加了一个不想要的约束,可以选中这个约束然后按delete键删除,或者在属性检查器中对其进行配置。
创建两个空间之间的相对距离,可以把鼠标移到一个控件上,然后按住右键,将鼠标拖动到另一个控件上,然后在弹出面板中选择想要的约束。
在iOS8之前,需要在代码中实现整个布局或多个storyboard,也可能两者都要,来为不同情况设计多个独立的界面。但是iOS8和Xcode 6之后,只使用单个storyboard就能设计出在各个方向以及不同设备上都能运行的自适应应用程序。
可以通过尺寸分类器来创建不同组的约束来对应不同的显示情况。
在工具栏中,可以看到一个叫做尺寸分类控件,外观上像一个文本为wAny hAny的标签。点击这个控件,会弹出一个包含9个单元格的网格的面板。
网格中的单元格对应不同的水平(宽度)以及垂直(高度)的尺寸分类组合。
尺寸分类是对设备高宽的一种大致分类。有两种具体的尺寸分类用来表示真机:紧凑(Compact)和标准(Regular)。还有第三种分类可以在设计工具里(和代码中)同时代表紧凑或标准:任意(Any)。
如图尺寸分类与设备以及方向的映射:
高宽都是紧凑的,映射的设备以及方向是出iPhone6 Plus之外的所有横屏iPhone
宽紧凑高标准的,映射的是所有竖屏的iPhone
宽标准高紧凑的,映射的是横屏的iPhone 6 Plus
高宽都是标准的,映射的是横屏和竖屏的所有iPad。
通常,紧凑意味着比标准小,不过有两个有趣的地方需要注意:
1.iPhone在竖屏模式下是紧凑宽度和标准高度,这个不难理解,因为在这个方向宽度比高度小。然而旋转到横屏模式后,宽高的尺寸分类都是紧凑的,并不是标准宽度和紧凑高度。唯一例外的就是大尺寸的iPhone 6 Plus,它才是标准的宽度和紧凑高度。这表示在决定布局时要考虑这两种尺寸分类。
2.iPad在横向和纵向都是标准宽度和标准高度,这意味着无法仅使用尺寸分类来确定iPad的方向。这在很多情况下并不是问题,因为iPad的屏幕相对大一些,而且比iPhone更接近正方形,可以在纵向和横向下使用同一中布局。
下面是图形的方式显示了尺寸分类的映射:
回到项目中,可以看到storyboard编辑器中的尺寸分类控件,默认是wAny hAny。这意味着storyboard 编辑器中的设计是对任意宽度和高度的尺寸分类有效。我么将其称为通用设计(base design)。
应该总是从通用设计开始,完成之后再根据需要修改通用设计。
通过在尺寸分类控件中选择某个组合,可以修改出适配它的设计并且不会对通用设计产生影响。
对于所有的iPhone(除iPhone 6 Plus以外)应该是紧凑高度和紧凑宽度,这样的尺寸分类应该就是wCompact 和HCompact了,然而我们想在iPhone 6 Plus上采用同样的设计,它的参数是wRegular 和hCompact。将它们归纳在一起,就可以得出,需要实现一种能在任意宽度和紧凑高度正常显示的设计。
选择后如下:
可以针对任何尺寸分类的组合使用3种方式对设计进行修改,所作的更改只会对当前尺寸分类组合所代表的设备和方向起作用。
1、可以添加、移除或修改约束。
2、可以添加或移除视图。
3、可以更改一些UIKit控件(在iOS8中有UILabel, UITextField, UITextView和UIButton)的字体。
现在所做的设计与通用设计有很多不同区别,因为所有的视图都会改变位置,所以需要移除所有存在的约束。在做改变之前,选中storyboard,打开辅助编辑器,在辅助编辑器跳转栏中选择Preview,就会打开storyboard的预览界面,它显示了iPhone纵向的外观。我们将使用这个预览界面来确保我们所作的修改不会对通用设计造成影响。
应该养成每次修改后就确认一次辅助编辑器以确保竖屏的设计没有受到影响。如果出现了问题,不要通过继续修改的方式来解决它,而是使用Command+Z快捷键来取消最后的几步操作来回退到之前的正确布局,然后再继续尝试。
要把控件原先的约束全部替换掉,在文档略图中选择它们并删除掉,这样做是错误的。删除约束会将其从所有的尺寸分类组合中移除。应该针对当前编辑的尺寸分类组合设计中卸载约束。
在storyboard中选择一个控件并打开尺寸检查器,可以找到原先添加的三条约束,双击顶端的约束,可以显示详细的信息,如下图:
可以看到底部的Installed复选框当前被勾选了。我们需要从这个设计中卸载此约束。方法是按下复选框左侧的加号按钮并在弹出的面板中选择Any Width | Compact Height。这样就添加了一个只针对wAny和hCompact布局的新复选框。取消它的勾选就可以从这个尺寸分类组合中卸载此约束,而这个约束在通用的设计中仍有效。
iOS9之后还有一种快捷的方法,就是选中控件后,单击Resolve Auto Layout Issues>Clear Constrains来卸载约束。
卸载约束后,可以看到在storyboard中的约束没有了,而且在文档略图和尺寸检查器中都变了灰色。可以通过选中每个控件并检查它们在尺寸检查器中是否灰色的来确认是否清空了所有的约束。
新增新的约束,点击Pin,在弹出框中取消勾选Constrains to margins复选框,然后在添加需要的约束。
在尺寸分类组合中新增的控件,只会在该分类尺寸组合里出现。
在新的尺寸分类组合里修改字体的大小,同样要在font中添加新的尺寸分类组合,然后在修改字体。