iOS

SizeClass探究

刚开始写iOS的时候,所有的分辨率都是320*480,所以UI布局都可以用代码写死。也写多iPad的代码,为了适应横屏,写了很多布局代码,当时除此之外,也没什么好的办法。后来有了iPhone5,有把原来的代码改改改……

#背景

iOS6,AutoLayout出来了,UI元素之间可以相对布局了。但这样只是解决了不同分辨率下的适配,界面中的元素不会增减,只是布局会调整。那么如果界面中的元素在不同的硬件下不一样呢?

毕竟,我们有了iPhone6,iPhone6 plus,以及马上就有的iWatch。一个应用,总不能在所有的设备上显示一样的界面吧?所以,苹果为了让我们不去写很多根据设备来调整界面元素的胶水代码,创造了SizeClass这个神奇的东西。

SizeClass是什么?

SizeClass是一个抽象的概念。对于任何尺寸,SizeClass给它定义了两种状态:Compact和Regular,分别代表不够宽和足够宽,如果两者都可以,那就是Any。

任何一个iOS的设备,不管是Phone、Pad还是Watch,都必然有长和宽;不管是长或者宽,它的尺寸必然是不够宽或者足够宽。到底是不够宽或者足够宽,这个苹果官方给我们规定好了。

  • iPhone4S,iPhone 5/5s,iPhone 6
    竖屏:(w:Compact h:Regular)
    横屏:(w:Compact h:Compact)

  • iPhone6Plus
    竖屏:(w:Compact h:Regular)
    横屏:(w:Regular h:Compact)

  • iPad
    竖屏:(w:Regular h:Regular)
    横屏:(w:Regular h:Regular)

  • AppleWatch(猜测)
    竖屏:(w:Compact h:Compact)
    横屏:(w:Compact h:Compact)

还有一个Any,指的是我并不关心尺寸,无论它是Compact或Regular,我都这么设计。

下图是IB中设计界面点开之后选择界面模式的视图。一共有9中模式,默认的是长和宽都是Any。
sizeclass_1.png

这些模式是有包含关系的。
sizeclass_2.png

如果在Any,Any模式下加入了一个View,那个不管是什么设备,都会显示这个View。
如果在Compact,Compact模式下加入了一个View,那么之后在iPhone4S,iPhone 5/5s,iPhone 6横屏的情况下才能看到,否则不可见。在IB中,一旦你把模式切到非Compact,Compact,该控件就会置灰。
如果在Compact,Any模式下加入了一个View,那么在iPhone中除了6plus横屏不可见,其余都可见,ipad均不可见。

总而言之,SizeClass就是对设备屏幕的抽象,不管以后苹果退出再多的分辨率,都能通过这9种模式包含起来。

SizeClass与AutoLayout的联系

SizeClass和AutoLayout是两码事,而且它们是相辅相成的。SizeClass解决了不同屏幕多种设计的问题,而AutoLayout解决的是不同频幕布局适配的问题。如果你不使用AutoLayout,则不能使用SizeClass;反之是可以的。

SizeClass还能干嘛?

  • 通过Image Asset为不同的SizeClass配置不同的图片
  • Label的FontSize根据不同的SizeClass设置不同的字号
  • 更多有待发现……

SizeClass与屏幕旋转

对于SizeClass来说,没有什么屏幕旋转的概念,有的只是切换SizeClass的模式,所以以下的几个api已经过时了:

1
2
3
4
5
6
@property(nonatomic, readonly) UIInterfaceOrientation interfaceOrientation

- willRotateToInterfaceOrientation:duration:
- willAnimateRotationToInterfaceOrientation:duration:
- didRotateFromInterfaceOrientation:
- shouldAutomaticallyForwardRotationMethods

取而代之的是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection 
withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
{
[super willTransitionToTraitCollection:newCollection
withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition:^(id <UIViewControllerTransitionCoordinatorContext> context) {
if (newCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact) {
//To Do: modify something for compact vertical size
} else {
//To Do: modify something for other vertical size
}
[self.view setNeedsLayout];
} completion:nil];
}

SizeClass很美好,但8.0之后才能使用,所以手头的项目暂时还用不了。

参考

iOS界面开发的大一统