UICollectionView 等分,出現一條縫?

今天下班的時候,和一個同事聊天的時候,發現在我們的項目中目前有一個小 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<UICollectionViewLayoutAttributes *> *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<UICollectionViewLayoutAttributes *> *)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,有設置的屬性和代理,那就更完美啦

發現重寫后達成了我們的目的,雖說這樣貌似解決了那個漏出背景色的那個問題,但有點撓,暫時還不知道有沒有什么更好的方法,有的話,歡迎告知。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一種新的協議。它實...
    香橙柚子閱讀 24,124評論 8 183
  • 今天去面試了,公司非常棒,我自己很喜歡,一面過了,明天二面,希望可以通過
    真壹閱讀 98評論 0 0
  • 其一,樹葉 你春天的姿色 還在我的心中 郁郁蔥蔥 我想將你擁抱 你卻卸了綠妝 嫁了寒風 ............
    喜亭_bf8f閱讀 215評論 7 10
  • 我愛你媽媽我們愛你的。我想你媽媽
    龍詩丹閱讀 215評論 0 1
  • 概要介紹 和HandlerThread一樣,IntentService也是Android替我們封裝的一個Helpe...
    tmp_zhao閱讀 452評論 0 4