今天下班的时候,和一个同事聊天的时候,发现在我们的项目中目前有一个小 Bug,就是并排 View的时候,在 iPhone 6 或 iPhone 6s 上会有一条缝出现,类似下图。
原本场景:
左边白色是一个 leftView,固定宽度 100;
右边是一个大的 rightView,宽度不固定,跟随屏幕变化;
右边 rightView 上并排铺满三个等宽的 三个 subView;
我的第一反应就是,直接自动布局啊,右边 rightView 以中间 的 subView 为轴,然后紧接着就没问题啦。就算并排多个 subView直接用Masonry + NSArray (MASHelper)也可以啦。然而别告知rightView是 UICollectionView。而且此种缝的情况也只会在 iPhone 6 或 iPhone 6s 上出现。
核心代码:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake((SCREEN_WIDTH - 100)/3.0, 100);
}
- (UICollectionViewFlowLayout *)flowLayout {
if (!_flowLayout) {
_flowLayout = [[UICollectionViewFlowLayout alloc] init];
_flowLayout.minimumLineSpacing = 0;
_flowLayout.minimumInteritemSpacing = 0;
}
return _flowLayout;
}
想着,出现这种情况,肯定是和 iPhone 6 或 iPhone 6s 上的屏幕宽 375有关,375 - 100 = 275,275 除以 3 等于 91.666666
此时也许我们可以先来一个
// 魔鬼数字先不管啊
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGFloat itemWidth = (SCREEN_WIDTH - 100)/3.0;
// itemWidth == 91.666666
if (SCREEN_WIDTH == 375) {
NSInteger row = indexPath.row % 3;
switch (row) {
case 0:
itemWidth = (NSInteger)itemWidth + 0.0;
break;
case 1:
itemWidth = (NSInteger)itemWidth + 1.0;
break;
case 2:
itemWidth = (NSInteger)itemWidth + 1.0;
break;
default:
break;
}
}
return CGSizeMake(itemWidth, 100);
}
这样看起来解决了,做一个 91,92,92的宽,但其实处理起来也显得比较麻烦,而且怎么感觉都怪怪的,并且假如苹果以后又出了一个这样类似要调整的机型,不可能再写吧,所以此处还需要调整。
后来再经过测试发现了一个奇怪的情况,在 iPhone 6p 上 那个宽度是等于itemWidth == 104.666667
,iPhone 6 上是 itemWidth == 91.666667
,按理说都不是整数,平分也会有缝隙啊,为什么 iPhone 6p 上没有呢???
再经过测试,例如直接将 iPhone 6上的屏幕4等分,9等分都会出现很明显空隙分割。特别是4等分的时候,width == 93.750000
,而且是两条缝隙,十分奇怪。
直接查看 View 层次发现,这个四个 UICollectionCell 的宽都是一样的。** width = 93.75 **。
于是为了验证,我在 iPhone 6上,用最直接的方法这样写:
// 此处没有用 for 循环 创建 和布局
UIView *oneView = [[UIView alloc] init];
oneView.backgroundColor = [UIColor redColor];
[self.view addSubview:oneView];
UIView *twoView = [[UIView alloc] init];
twoView.backgroundColor = [UIColor yellowColor];
[self.view addSubview:twoView];
UIView *threeView = [[UIView alloc] init];
threeView.backgroundColor = [UIColor blueColor];
[self.view addSubview:threeView];
UIView *fourView = [[UIView alloc] init];
fourView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:fourView];
[oneView mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.mas_equalTo(@0);
make.centerY.equalTo(self.view.mas_centerY);
make.height.mas_equalTo(@100);
}];
[twoView mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.centerY.width.equalTo(oneView);
make.leading.equalTo(oneView.mas_trailing);
}];
[threeView mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.centerY.width.equalTo(twoView);
make.leading.equalTo(twoView.mas_trailing);
}];
[fourView mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.centerY.width.equalTo(threeView);
make.trailing.mas_equalTo(@0);
make.leading.equalTo(threeView.mas_trailing);
}];
发现这样,它又不会出现空隙,四个 View 紧紧靠在一起。但是我却是发现它的宽度变成 94,93.5,94,93.5。
所以说,通过两个宽度对比(93.75和94,93.5),在 iPhone6 上UICollectionViewFlowLayout和普通布局做的处理是有区别的。同时惊讶的事情发生了,iPhone 6plus 也出现这种情况了。
可以归纳为iPhone6 和iPhone 6plus UICollectionView四等分时总是不能充满屏幕, 有两根线漏出背景色,因此这个问题应该是和UICollectionViewFlowLayout 相关的。
所以我尝试重写UICollectionViewFlowLayout
啦。
@interface PQCollectionViewLayout : UICollectionViewLayout
@end
#import "PQCollectionViewLayout.h"
@interface PQCollectionViewLayout ()
@property(nonatomic,strong) NSMutableArray *attributeArr;
@end
@implementation PQCollectionViewLayout
- (NSMutableArray *)attributeArr{
if (_attributeArr == nil) {
_attributeArr = [[NSMutableArray alloc] init];
}
return _attributeArr;
}
- (void)prepareLayout{
[super prepareLayout];
[self.attributeArr removeAllObjects];
// 获取cell的size
for (NSInteger i=0, count = [self.collectionView numberOfItemsInSection:0]; i < count; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
[self.attributeArr addObject:attributes];
}
}
- (CGSize)collectionViewContentSize{
UICollectionViewLayoutAttributes *attribute = self.attributeArr.lastObject;
return CGSizeMake(0, CGRectGetMaxY(attribute.frame));
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
return self.attributeArr;
}
/**
* 返回每个cell的布局属性
*/
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
// CGSize : width = (SCREEN_WIDTH - 100)/3.0; height = 100;
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
CGFloat itemWidth = ([UIScreen mainScreen].bounds.size.width - 100)/3.0;
attributes.frame = CGRectMake(indexPath.row % 3 * itemWidth, indexPath.row / 3 * 100, itemWidth, 100);
return attributes;
}
@end
- (PQCollectionViewLayout *)flowLayout {
if (!_flowLayout) {
_flowLayout = [[PQCollectionViewLayout alloc] init];
}
return _flowLayout;
}
ps:上面重写只针对这边特殊需求的三等分,其他情况需要根据attributes.frame 自由设置, 当然有需要写成一个自己UICollectionViewFlowLayout,有设置的属性和代理,那就更完美啦
发现重写后达成了我们的目的,虽说这样貌似解决了那个漏出背景色的那个问题,但有点挠,暂时还不知道有没有什么更好的方法,有的话,欢迎告知。