在肾6之前,或者更早,很多人都喜欢手写UI,即使iOS6后Autolayout也不太流行,Storyboard用的人也不多,特别是在国内大家都抓着iOS5不放,因此在肾6后,对这种项目怎样花最小成本适配是首要问题——新项目可以使用StoryBoard结合Autolayout、Size Classes解决——但对300多个类的大型项目来说,一方面要有新功能,一方面进行全部重构不现实。
Launch Screen
要适配iPhone6(6+),只要增加两个启动图片或者Launch Screen xib即可:
For iPhone 6: |
---|
750 x 1334 (@2x) for portrait |
1334 x 750 (@2x) for landscape |
For iPhone 6 Plus: |
---|
1242 x 2208 (@3x) for portrait |
2208 x 1242 (@3x) for landscape |
就跟iPhone5适配一样,如果主要去过启动图片来决定,这里多了一个Launch Screen,如果不进行设置,在iPhone6(6+)就会以iPhone5的屏幕为基准进行等比拉伸。
无Autolayout适配?
前面说了,旧项目无Autolayut,剩下的问题怎么处理?其实还好,就目前游戏助手的项目适配经验来说,虽然界面和细节都非常多,但就单个界面来说要改动的并不多,在屏幕适配方面并没有安卓端那样多的烦恼,即使不使用Autolayout,大部分可以在xib中进行简单的Autoresizing设置就可以完成适配,主要问题集中在两点:
- 宽度重新计算
- 如何取得正确的宽度
宽度重新计算
xib文件如果没有使用Autolayout的话,先在xib中进行Autoresizing设置:

代码生成的UI,则要做更多的事情:
- 代码不再写死320,改用容器bounds.size.width
- UI水平位置,长度按需要结合父容器重新计算
但还会有另外一个问题:宽度有时候不对,返回320,为什么?
如何取得正确的宽度:
即使用代码生成UI,这个问题在iPhone 6之前几乎不存在,因为只有320,所以在viewDidLoad中建立的UI基本正确,所以大家都这样处理:
- (void)viewDidLoad {
[super viewDidLoad];
UILabel *label = [UILabel alloc] initWithFrame:CGRectMake(0,100,self.view.frame.size.width,30);
label.backgroundColor = [UIColor redColor];
[self.view addSubview:label];
}
在添加完LaunchScreen后,会发现Label的宽度少了一截,并没有如期的满宽度,为什么?

经过Log,发现在viewDidLoad中的view.frame居然还是320,必须在viewWillAppear后才是375!
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"view did load frame from xib:%@", NSStringFromCGRect(self.view.frame));
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(@"view Will Appear frame from xib:%@", NSStringFromCGRect(self.view.frame));
}
Log信息:

其实这里一直这样,在viewDidLoad中取得的值一直是xib中原始的view尺寸,与是否Autolayout或Size Class无关,只是之前只有一个屏幕宽度,隐藏了问题而已。所以正确的宽度必须在viewWillAppear中取得。
[UIScreen mainScreen].bounds.size.width总能得到正确的宽度。
如果Simulated Metrics的Size改为其它屏幕,也会是同样的结果。


同样的设置再用StoryBoard测试,不会出现此问题,所以此问题仅限于单独使用xib的情况。
如果代码设置autoresizingMask呢?
- (void)viewDidLoad {
[super viewDidLoad];
UILabel *label = [UILabel alloc] initWithFrame:CGRectMake(0,100,self.view.frame.size.width,30);
label.backgroundColor = [UIColor redColor];
label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[self.view addSubview:label];
}
设置autoresizingMask也是可以达到适配iPhone6效果的。
注:想让View居右,用的是UIViewAutoresizingFlexibleLeftMargin,即左边的margin是可变的,而非UIViewAutoresizingFlexibleRightMargin
虽然可以用autoresizingMask得到想要的显示效果,但实际上在viewDidLoad内宽度依然是不正确的,直到viewWillAppear。
所以设置UI布局最合理的时机是viewWillAppear。 如果使用viewWillLayout进行布局,因为会多次调用,(当Controller显示时,子Controller隐藏时),所以必须进行判定,以免过于频繁的操作。
关于最佳布局时机的问题,感谢同事项同学建议:
但是最后一句话其实有点问题
对于VC来说设置布局的最合理时机应该是viewWillLayoutSubviews或者viewDidLayoutSubviews (推荐后者)
对于UIView来说设置布局的最合理时机是为layoutSubviews如果选择viewWillAppear作为布局时机,很有可能触发一些不必要的布局 (比如modal VC被dismiss后导致当前的topViewController调用到viewWillAppear这种)
参考文献:
- iOS UIViewController lifecycle
- Where to progmatically lay out views in iOS 5 (and handling orientation changes)
【完】
网友评论