GeekerProbe

水滴石穿 Keeping faith.      --- wtlucky's Blog

一个特殊的iPhone6 Plus适配问题

| Comments

最近项目在搞适配,目前的适配原则是不改变既有的设计图的设计样式,使用@3x的图片去进行完美适配。即不涉及到某一个模块在iPhone5及以下的设备上是一个展示样式,在iPhone6或着iPhone6 Plus上是另外的一个展示样式。单纯是这样的需求通过Auto ResizingAutoLayout就完全可以应付的了。以前硬编码写的view的frame通过乘上一个屏幕放大的比例系数也可以搞定。

可是目前设计同学提出在一个使用collection view的页面中,之前是通过各种设备使用同一个大小的cell,不同的屏幕上拉大的是cell之间的间距来进行适配。现如今要改成只有在6 Plus上要将cell上半部分等比例放大,cell中下半部分的文字的字号也放大。目前的需求就是这个样子,其实我觉得这样适配就不是苹果的设计规范,按道理说屏幕大了看的内容多才对,这样搞个等比例放大,跟没有适配在兼容模式下运行的效果似地。不过需求来了还是得搞。

这个cell本来就是使用AutoLayout做的,但是之前是定高定宽的,图片的宽度被限制死了,即使是在collocation view的代理方法中将cell设大,cell的图片也不会变大。而且还需要把字体一并放大,以及图片左上和右下的两个图片的位置是要成比例设置的,这样之前设置的heading spacetrailing space是固定值,也不能达到要求。先来看一下这个cell,因为项目的保密性我没有展示全部的内容,只是列举了一部分,但足以说明问题。

因为使用的是xcode6,苹果提供了Size Classes这样强大的一个功能,为的是制作adaptive UI。就是只制作一套UI,但是可以适配多个屏幕尺寸以及选装方向,之前没有仔细研究过这个新特性,只是觉得他应该能应付当前的需求,因为使用它可以为每一种size设置一套constraint和字体大小。很好很强大!

但是当开始使用时发现,没有一个size是能够单独区分出6 Plusportrait模式的,到时能区分出landscape模式。6 Plusportrait模式使用的是Regular heightCompact width,其他的设备的portrait模式使用的也是Regular heightCompact width。但是Any heightCompact width这个size对应的是6 Plus以外其他设备的portraitlandscape模式。如图所示,

这里正好不包括6 Plus,分别设置了这两种size发现不是预期的效果,所有的手机都使用了Regular heightCompact width的这个size。后来有看见了这个优先级的表格,

一旦设置了这个size那么就会优先加载这个size,所以这条路目前是行不通的,我觉得一定有其他的方法来通过Size Classes解决,或者通过代码修改优先级,或者使用某种方法标识6 Plus。由于我时间比较紧急,所以就没有继续使用这种方式,有知道的大神求告知啊,感激不尽!

Size Classes行不通,又想了其他两种方案,一个是为6 Plus单独制作一个xib,让collection view在6 Plus上加载这个xib上的cell;另外一个是修改现有的cell上的constraints把固定图片的大小constraint干掉搞成自适应的,自适应不了的constraint通过IBOutlet在代码中进行修改。权衡了一下这两个方案,第一个目前的工作量比较小,但是后期维护很恶心,而且这种做法实在是太low。而第二种虽然开始开上去很复杂,工作量很大,但是搞定之后,维护修改起来也容易很多,毕竟只有一个UI。

所以选择第二种开工,自适应很好搞,把最大的那个圆圈与父view的headingtrailing设为0即可,难的是等比例,虽然用AutoLayout有几个月了但是用得都是headingtrailingverticalhorizontaltopbottom 还有widthheight这几个constraint,他们就能解决我之前遇到的所有布局问题,连alignment的那几个constraint我都很少使用。但是这次需要用到Aspect ratio了,之前一直不知道这咋用,感谢这次需求让我知道了如何用他,最大的那个圆圈是正方形设置了左右间距就确定了宽度,而高度的确定就用Aspect ratio设置为1:1即可,同样圆圈左上和右下的图也是需要等比例放大的,他们的比例也是通过Aspect ratio来设置,这里的比例按照设计图写一下即可。这里发现xcode一个很奇怪的问题,就是按住ctrl从一个view拖向另外一个view选择Aspect ratio的时候,xcode为你生成的是一个view的height与另一个view的width的比,这个我一直不是很理解,虽然如果你在设置Aspect ratio之前把他们的frame设为正确的话,生成的比例是正确的,但是这样真的很奇怪,可读性特别差,为什么要一个高比上另外一个的宽呢?我承认我数学学的不好,这里可能有其他的深刻含义,但是我觉得好奇怪,如果有人知道欢迎留言评论!所以这里我又手动的把一个view的height改为width,即宽比上宽,按照设计图修改一下比例。还有一个问题是圆圈的左上有右下的view的位置是要相应改变的,也是按照比例,设置固定的值肯定是不行的,因为值也是会变得,这里再次感谢这个需求,让我又一次加深的AutoLayout的理解,AutoLayout中的约束其实是一个二元一次方程,如图所示

First item = Second item * Multiplier + Constant, 一个值是可以通过另外一个值通过这个方程式计算出来的,而我们所加的约束就是设置了MultiplierConstant,再加上优先级,两者的属性(上下左右宽高等)以及两者的关系(大于小于等于),这些共同组成了一个constraint。 xcode默认创建的constraintMultiplier1,我之前使用的所有constraint也都是使用的是1,从没有改变过他,从方程式来看这里是可以按比例设置的。不得不说AutoLayout真的很强大,自己用到的仅仅是冰山一角。

那圆圈右下角的view举例子,首先设置他的x轴距离,据父view一个是heading一个是trailing,因为父view的heading0,无论Multiplier设置什么相乘都是零,所以只能用trailing,因为我们事先已经按照设计图将一个尺寸的界面拼出来了,当设置了trailing之后,xcode生成了一个Multiplier1Constant为一个固定值的constraint,这样不对,不能够按比例移动x轴位置,所以我们把Constant设为0,由公式算出MultiplierFirst item / Second item并进行设置。确定了x方向的位置还需要y方向的位置,y这里又出现了另外一个坑,y方向父view的top0不能这是比例,bottom由于有Label所以bottom的值是不确定的,所以就不能与父view做约束了,只能选择与圆圈做约束,这里使用的是align bottom。同理因为是按比例放大,这个constraint也不能使用定值,所以Constant设为0,公式算出Multiplier并设置。同样圆圈左上的view也这样设置即可。如此一来cell上半部分等比例放大的问题就搞定了。

cell下半部分Label之间的间距这个是不能自适应的,6 Plus和其他设备是两个不同的值,这样就只能把他们的constraint拿到代码中去进行修改,label上字体也是只能在代码中cell第一次加载时判断为6 Plus就将他们的字体放大。将这一部分逻辑放在了aweakFromNib

1
2
3
4
5
6
7
8
9
10
11
12
13
- (id)initWithCoder:(NSCoder *)aDecoder
{
    if (fequal(ScreenWidth, 414.0f)) {
        self.titleLabel.font = [UIFont systemFontOfSize:16.0f];
        self.memberNumLabel.font = [UIFont systemFontOfSize:15.0f];
        self.infoLabel.font = [UIFont systemFontOfSize:13.0f];

        self.icoTopConstraint.constant = 8.0f;
        self.nameTopConstraint.constant = 33.0f;
        self.memberCountTopConstraint.constant = 7.0f;
        self.infoTopConstraint.constant = 10.0f;
    }
}

这里要说一下,判断6 Plus不能通过设备号去判断,iPhone7,1iPhone7,2虽然是iPhone6iPhone6 Plus没错,但是我们是在渲染界面,iPhone6iPhone6 Plus是有一个放大模式的,在放大模式下iPhone6 Plus的屏幕尺寸是iPhone6的,iPhone6的屏幕尺寸是iPhone5的,所以如果通过设备号去判读那么渲染出来就是错误的,正确的方式是通过屏幕的尺寸来判断即[UIScreen mainScreen].bounds.size


写的很乱,因为是当天搞的,当天就记录下来,怕以后忘了,文笔不好,就凑合看吧,最后总结一下:

  1. Size Classes还有待研究,如何区分出iPhone6 Plus
  2. 学会了使用Aspect ratio,用于标记一个view的宽高比或者两个view的宽高比
  3. AutoLayout中使用Multiplier进行数值成比例改变的需求
  4. 在界面布局是不要使用设备号进行判别,要使用屏幕尺寸进行判断

参考资料

Adaptivity and Layout

Size Classes Design Help

ADAPTIVE LAYOUTS FOR iPHONE 6

————————————

Comments