UICollectionViewFlowLayout具有可变单元格宽度和高度的空白空间

luk*_*r90 6 objective-c ios uicollectionview uicollectionviewlayout

我正在尝试通过继承UICollectionViewFlowLayout为UICollectionView定义自定义流布局.我想要的布局看起来像这样:

布局

如您所见,我已将集合视图沿水平中间分割分成2行.顶行被分成三列,给出3列,底行分成两列,给出2列.

一切似乎工作正常,直到你向右滚动(集合视图滚动到UICollectionViewScrollDirectionHorizo​​ntal),并在5个单元格完成渲染后看到一个很大的空间:

布局

我不知道为什么会发生这种情况,但是看起来空的空间看起来与顶行的单元格大致相同; 集合视图宽度的三分之一.

这是我如何设置UICollectionView和UICollectionViewFlowLayout子类

- (void)loadView {
    [super loadView];
    [self setupCollectionView];
}

- (void)setupCollectionView {
    CustomFlowLayout *flowLayout = [[CustomFlowLayout alloc] init];
    flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    flowLayout.minimumInteritemSpacing = 0.0;
    flowLayout.minimumLineSpacing = 0.0f;

    CGRect frame = CGRectMake(0, 0, 748, 1024);
    UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:frame collectionViewLayout:flowLayout];

    [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:CollectionViewCellID];

    collectionView.delegate = self;
    collectionView.dataSource = self;

    collectionView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;

    collectionView.backgroundColor = [UIColor whiteColor];

    collectionView.pagingEnabled = YES;


    self.collectionView = collectionView;

    [self.view addSubview:self.collectionView];
}

#pragma mark - UICollectionViewDataSource
- (NSInteger )numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 1;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {

    return 5;
}
Run Code Online (Sandbox Code Playgroud)

集合视图中项目的大小由给定部分的布局配置定义,因此我实现collectionView:layout:sizeForItemAtIndexPath:如下:

- (CGSize)collectionView:(UICollectionView *)collectionView
                  layout:(UICollectionViewLayout*)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    return [collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath].size;

}
Run Code Online (Sandbox Code Playgroud)

我的UICollectionViewLayout的自定义子类实现如下:

@implementation CustomFlowLayout

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray* attributesToReturn = [super layoutAttributesForElementsInRect:rect];
    for (UICollectionViewLayoutAttributes* attributes in attributesToReturn) {
        if (nil == attributes.representedElementKind) {
            NSIndexPath* indexPath = attributes.indexPath;
            attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
        }
    }
    return attributesToReturn;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes* currentItemAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];

    if (!currentItemAttributes) {
        currentItemAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    }

    float height = self.collectionView.frame.size.height;
    float width = self.collectionView.frame.size.width;

    CGRect frame = CGRectZero;    
    switch (indexPath.row) {
        case 0:
            frame.size = CGSizeMake(width/3, height/2);
            frame.origin = CGPointMake(0, 0);
            break;
        case 1:
            frame.size =  CGSizeMake(width/3, height/2);
            frame.origin = CGPointMake(width/3, 0);
            break;
        case 2:
            frame.size =  CGSizeMake(width/3, height/2);
            frame.origin = CGPointMake(2*width/3, 0);
            break;
        case 3:
            frame.size =  CGSizeMake(width/2, height/2);
            frame.origin = CGPointMake(0, height/2);
            break;
        case 4:
            frame.size =  CGSizeMake(width/2, height/2);
            frame.origin = CGPointMake(width/2, height/2);
            break;
        default:
            break;
    }

    currentItemAttributes.frame = frame;
    currentItemAttributes.size = frame.size;
    return currentItemAttributes;
}
Run Code Online (Sandbox Code Playgroud)

任何人都知道为什么在渲染完所有细胞之后我有大的空白空间?或者有没有人有更好的方法来渲染我所追求的布局.所有代码都可以在这里作为示例XCode项目使用.非常感谢答案,提示,想法,拉取请求.

luk*_*r90 4

问题似乎是,当有两行具有不同宽度的单元格时,集合视图的 contentSize 的计算方式会在右侧留下空白区域。解决这个问题需要一个简单的方法:

- (CGSize)collectionViewContentSize {
    return CGSizeMake(1024, 748);
}
Run Code Online (Sandbox Code Playgroud)

使用此处的更改更新了 Github 存储库。希望这对将来的人有帮助。