Cells order in UICollectionView

后端 未结 2 533
既然无缘
既然无缘 2020-12-11 10:30

I need to create a UICollectionView with cells of different sizes (1x1, 2x2, 2x1, 3x2.5). I\'ve already code to add cells depending on which size they are using

相关标签:
2条回答
  • 2020-12-11 10:51

    Here it's the same logic as Larme suggested. But with less hardcode and which give you the possibility of setting the number of items you want without adding new case:.

    I call "pattern" a set of 5 items. So first I define constant values:

    #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
    

    Then I create a custom layout with 2 properties NSMutableArray *layoutAttributes and CGFloat contentHeight in which I need to override the methods:

    - (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);
    }
    

    Then assign this custom layout to self.collectionView.collectionViewLayout and that's it. You can find more information and swift version here.

    0 讨论(0)
  • 2020-12-11 11:10

    A sample example by subclassing UICollectionViewLayout. All values are hard coded, just to explicit the logic behind it. Of course, that could be optimized.

    @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
    

    Then, you just have to call :

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

    Rendering :

    0 讨论(0)
提交回复
热议问题