UICollectionView 等分,出现一条缝?

今天下班的时候,和一个同事聊天的时候,发现在我们的项目中目前有一个小 Bug,就是并排 View的时候,在 iPhone 6 或 iPhone 6s 上会有一条缝出现,类似下图。

UICollectionView 等分,出现一条缝?_第1张图片
缝隙

原本场景:
左边白色是一个 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,而且是两条缝隙,十分奇怪。

UICollectionView 等分,出现一条缝?_第2张图片
两条缝隙

直接查看 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,有设置的属性和代理,那就更完美啦

发现重写后达成了我们的目的,虽说这样貌似解决了那个漏出背景色的那个问题,但有点挠,暂时还不知道有没有什么更好的方法,有的话,欢迎告知。

你可能感兴趣的:(UICollectionView 等分,出现一条缝?)