【问题标题】:Cells order in UICollectionViewUICollectionView 中的单元格顺序
【发布时间】:2017-02-21 10:33:17
【问题描述】:

我需要使用不同大小(1x1、2x2、2x1、3x2.5)的单元格创建一个UICollectionView。我已经编写了代码来根据它们使用的大小添加单元格collectionView:layout:sizeForItemAtIndexPath:

这是预期结果(单元格 1 和 3 必须位于单元格 2 的左侧):

但目前的结果是:

我的(丑陋的)当前代码是(self.cellSize = screen width / 3):

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

    CGFloat size = self.cellSize;

    if (indexPath.item == 0) {
        return CGSizeMake(self.cellSize * 3.f, self.cellSize * 2.5f);
    }

    if (indexPath.item == 1) {
        return CGSizeMake(self.cellSize, self.cellSize);
    }

    if (indexPath.item == 2) {
        return CGSizeMake(self.cellSize * 2.f, self.cellSize * 2.f);
    }

    if (indexPath.item == 3) {
        return CGSizeMake(self.cellSize, self.cellSize);
    }

    if (indexPath.item == 4) {
        return CGSizeMake(self.cellSize * 2.f, self.cellSize);
    }

    if (indexPath.item == 5) {
        return CGSizeMake(self.cellSize, self.cellSize);
    }

    if (indexPath.item == 6) {
        return CGSizeMake(self.cellSize, self.cellSize);
    }

    if (indexPath.item == 7) {
        return CGSizeMake(self.cellSize * 2.f, self.cellSize);
    }

    if (indexPath.item == 8) {
        return CGSizeMake(self.cellSize * 3.f, self.cellSize * 2.5f);
    }

    return CGSizeMake(size, size);
}

有没有办法指定单元格 3 必须在单元格 1 上方,但在单元格 2 的左侧?

我不想做一个不会改变的静态布局,因为每个单元格将来可能有不同的大小。例如,单元格 2 可以是 2x1 大小...

这样做的最佳方法是什么?我期待为UICollectionViewLayout 指定一个流程(如“从顶部”),但它不是那样工作的......

【问题讨论】:

  • 我认为你必须继承 UICollectionViewLayout 的子类,你会给每个单元格一个框架。

标签: ios objective-c uicollectionview


【解决方案1】:

继承 UICollectionViewLayout 的示例。 所有值都是硬编码的,只是为了明确其背后的逻辑。当然,这可以优化。

@interface CustomCollectionViewLayout ()

@property (nonatomic, strong) NSMutableDictionary *cellLayouts;
@property (nonatomic, assign) CGSize              unitSize;

@end

@implementation CustomCollectionViewLayout


-(id)initWithSize:(CGSize)size
{
  self = [super init];
  if (self)
  {
    _unitSize = CGSizeMake(size.width/3,150);
    _cellLayouts = [[NSMutableDictionary alloc] init];
  }
  return self;
}
-(void)prepareLayout
{

  for (NSInteger i = 0; i < [[self collectionView] numberOfItemsInSection:0]; i ++)
  {
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    CGRect frame;
    switch ([indexPath item])
    {
      case 0:
        frame = CGRectMake(0, 0, _unitSize.width*3, _unitSize.height*2.5);
        break;
      case 1:
        frame = CGRectMake(0, _unitSize.height*2.5, _unitSize.width, _unitSize.height);
        break;
      case 2:
        frame = CGRectMake(_unitSize.width, _unitSize.height*2.5, _unitSize.width*2, _unitSize.height*2);
        break;
      case 3:
        frame = CGRectMake(0, _unitSize.height*2.5+_unitSize.height, _unitSize.width, _unitSize.height);
        break;
      case 4:
        frame = CGRectMake(0, _unitSize.height*2.5+_unitSize.height+_unitSize.height, _unitSize.width*2, _unitSize.height);
        break;
      case 5:
        frame = CGRectMake(_unitSize.width*2, _unitSize.height*2.5+_unitSize.height+_unitSize.height, _unitSize.width, _unitSize.height);
        break;
      case 6:
        frame = CGRectMake(0, _unitSize.height*2.5+_unitSize.height+_unitSize.height+_unitSize.height, _unitSize.width, _unitSize.height);
        break;
      case 7:
        frame = CGRectMake(_unitSize.width, _unitSize.height*2.5+_unitSize.height+_unitSize.height+_unitSize.height, _unitSize.width*2, _unitSize.height);
        break;
      case 8:
        frame = CGRectMake(0, _unitSize.height*2.5+_unitSize.height+_unitSize.height+_unitSize.height+_unitSize.height, _unitSize.width*3, _unitSize.height*2.5);
        break;
      default:
        frame = CGRectZero;
        break;
    }
    [attributes setFrame:frame];
    [[self cellLayouts] setObject:attributes forKey:indexPath];
  }
}

-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
  NSMutableArray *retAttributes = [[NSMutableArray alloc] init];
  for (NSIndexPath *anIndexPath in [self cellLayouts])
  {
    UICollectionViewLayoutAttributes *attributes = [self cellLayouts][anIndexPath];
    if (CGRectIntersectsRect(rect, [attributes frame]))
    {
      [retAttributes addObject:attributes];
    }
  }
  return retAttributes;
}

-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{

  return [self cellLayouts][indexPath];
}

-(CGSize)collectionViewContentSize
{
  return CGSizeMake(_unitSize.width*3, _unitSize.height*9);
}

@end

然后,您只需调用:

CustomCollectionViewLayout *layout = [[CustomCollectionViewLayout alloc] initWithSize:self.myCollectionView.bounds.frame.size];
[self.myCollectionView setCollectionViewLayout:layout];

渲染:

【讨论】:

  • 哇!它完美地工作。非常感谢你。我将尝试重写一些硬编码部分。
  • @Larme,真的很有帮助。再次感谢,+1 投票
【解决方案2】:

这与 Larme 建议的逻辑相同。但使用较少的硬代码,您可以在不添加新的case: 的情况下设置所需的项目数量。

我将“模式”称为一组 5 个项目。所以首先我定义常量值:

#define MAX_COLUMN              3 // Max columns in the pattern
#define MAX_LINE_PER_PATTERN    3 // Max lines in the pattern
#define PATTERN_ITEM_COUNT      5 // Max items in the pattern

然后我创建一个自定义布局,其中包含两个属性 NSMutableArray *layoutAttributesCGFloat contentHeight,我需要在其中覆盖方法:

- (void)prepareLayout{
    [super prepareLayout];

    if (!self.layoutAttributes){
        self.layoutAttributes = [[NSMutableArray alloc] init];

        CGFloat cellWidth = self.collectionView.frame.size.width / MAX_COLUMN;
        CGFloat cellHeight = cellWidth;
        self.contentHeight = 0.f;

        for (int item = 0 ; item < [self.collectionView numberOfItemsInSection:0] ; item ++){

            CGFloat width, height = 0.f;
            CGFloat xPos, yPos = 0.f;

            NSInteger patternCount = (NSInteger)((CGFloat)item / (CGFloat)PATTERN_ITEM_COUNT);
            NSInteger currentIndex = item % PATTERN_ITEM_COUNT;
            switch (currentIndex) {
                case 0:
                {
                    xPos = 0.f;
                    yPos = 0.f + MAX_LINE_PER_PATTERN * cellHeight * patternCount;
                    width = cellWidth;
                    height = cellHeight;
                    self.contentHeight += cellHeight;
                    break;
                }
                case 1:
                {
                    xPos = cellWidth;
                    yPos = 0.f + MAX_LINE_PER_PATTERN * cellHeight * patternCount;
                    width = cellWidth * 2.f;
                    height = cellHeight * 2.f;
                    self.contentHeight += cellHeight;
                    break;
                }
                case 2:
                {
                    xPos = 0.f;
                    yPos = cellHeight + MAX_LINE_PER_PATTERN * cellHeight * patternCount;
                    width = cellWidth;
                    height = cellHeight;
                    break;
                }
                case 3:
                {
                    xPos = 0.f;
                    yPos = 2.f * cellHeight + MAX_LINE_PER_PATTERN * cellHeight * patternCount;
                    width = cellWidth * 2.f;
                    height = cellHeight;
                    self.contentHeight += cellHeight;
                    break;
                }
                case 4:
                {
                    xPos = 2.f * cellWidth;
                    yPos = 2.f * cellHeight + MAX_LINE_PER_PATTERN * cellHeight * patternCount;
                    width = cellWidth;
                    height = cellHeight;
                    break;
                }
                default:
                    NSLog(@"error with index");
                    break;
            }
            UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForRow:item inSection:0]];
            attr.frame = CGRectMake(xPos,
                                    yPos,
                                    width,
                                    height);
            [self.layoutAttributes addObject:attr];
        }
    }
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
    NSMutableArray *currentAttributes = [NSMutableArray new];
    for (UICollectionViewLayoutAttributes *attr in self.layoutAttributes) {
        if (CGRectIntersectsRect(attr.frame, rect))
        {
            [currentAttributes addObject:attr];
        }
    }
    return currentAttributes;
}

- (CGSize)collectionViewContentSize{
    return CGSizeMake(self.collectionView.frame.size.width, self.contentHeight);
}

然后将此自定义布局分配给self.collectionView.collectionViewLayout,就是这样。您可以找到更多信息和快速版本here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-21
    • 1970-01-01
    • 1970-01-01
    • 2017-06-09
    • 2023-03-27
    • 2014-07-29
    • 2013-06-18
    • 1970-01-01
    相关资源
    最近更新 更多