IOS: Separate background colors of a section on a UICollectionView

I have a UICollectionView with a gray background, however I want one of my sections to have a white background. I found that it was not as easy as I had hoped (i.e. a section having an attribute that I could just set).

From a glance at How to change the background color for an entire section in a UICollectionView? It was suggested to use the decor view and this question UICollectionView Decoration View helped me change the color of the section by subclassing UICollectionReusableViewand UICollectionViewFlowLayout.

My problem is that I cannot get the height of the section (which is dynamic) to set the height of the UIView, and also the beginning of my next section is empty until the reloadData request appears on it.

Here is my code WhiteBackgroundCollectionReusableView Class::

#import <UIKit/UIKit.h>

@interface WhiteBackgroundCollectionReusableView : UICollectionReusableView

@end

@implementation WhiteBackgroundCollectionReusableView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        [self setBackgroundColor:[UIColor redColor]];
    }
    return self;
}

@end

WhiteBackgroundCollectionViewFlowLayout Class:

#import <UIKit/UIKit.h>

#import "WhiteBackgroundCollectionReusableView.h"

@interface WhiteBackgroundCollectionViewFlowLayout : UICollectionViewFlowLayout

@end

@implementation WhiteBackgroundCollectionViewFlowLayout

- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code

        [self registerClass:[WhiteBackgroundCollectionReusableView class] forDecorationViewOfKind:@"WhiteSection"];
    }
    return self;
}

- (UICollectionViewLayoutAttributes*)layoutAttributesForDecorationViewOfKind:(NSString*)decorationViewKind atIndexPath:(NSIndexPath*)indexPath
{
    UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:decorationViewKind withIndexPath:indexPath];

    if(indexPath.section == 0) {
        layoutAttributes.frame = CGRectMake(0.0, 0.0, self.collectionViewContentSize.width, 100);

        layoutAttributes.zIndex = -1;
    }

    return layoutAttributes;
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSMutableArray *allAttributes = [[NSMutableArray alloc] initWithCapacity:4];

    [allAttributes addObject:[self layoutAttributesForDecorationViewOfKind:@"WhiteSection" atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]];

    for(NSInteger i = 0; i < [self.collectionView numberOfItemsInSection:0]; i++)
    {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForItemAtIndexPath:indexPath];
        [allAttributes addObject:layoutAttributes];
    }

    return allAttributes;
}

@end

Then I assign my stream layout to my UICollectionView in mine UICollectionViewControllerin viewDidLoad:

[_collectionView setCollectionViewLayout:[[WhiteBackgroundCollectionViewFlowLayout alloc] init]];

Any idea that I can move from here

UPDATE: I fixed the problem when the next section was not showing. To do this, I needed to change zIndex to 1, so my function layoutAttributesForElementsInRectnow looks like this:

- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSArray *array = [super layoutAttributesForElementsInRect:rect];

    for(UICollectionViewLayoutAttributes *attributes in array) {
        attributes.zIndex = 1;
    }

    NSMutableArray *newArray = [array mutableCopy];

    [newArray addObject:[self layoutAttributesForDecorationViewOfKind:@"WhiteSection" atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]];

    for(NSInteger i = 0; i < [self.collectionView numberOfItemsInSection:0]; i++) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForItemAtIndexPath:indexPath];
        [newArray addObject:layoutAttributes];
    }

    array = [NSArray arrayWithArray:newArray];

    return array;
}

So now all I need is a way to get the section height! PLEASE HELP! :)

+4
source share
2 answers

My solution is available at https://github.com/s-atif-jamil/CollectionSectionView

UnderBackgroundLayout.h

@interface SectionBackgroundLayout : UICollectionViewFlowLayout

@property (assign, nonatomic) BOOL alternateBackgrounds;
@property (strong, nonatomic) NSArray *decorationViewOfKinds;

@end

UnderBackgroundLayout.m

#import "SectionBackgroundLayout.h"

@interface SectionBackgroundLayout ()

@property (strong, nonatomic) NSMutableArray *itemAttributes;

@end

@implementation SectionBackgroundLayout


- (void)prepareLayout
{
    [super prepareLayout];
    self.itemAttributes = [NSMutableArray new];

    NSInteger numberOfSection = self.collectionView.numberOfSections;
    for (int section=0; section<numberOfSection; section++)
    {
        if (!self.alternateBackgrounds && section == self.decorationViewOfKinds.count)
            break;

        NSString *decorationViewOfKind = self.decorationViewOfKinds[section % self.decorationViewOfKinds.count];
        if ([decorationViewOfKind isKindOfClass:[NSNull class]])
            continue;

        NSInteger lastIndex = [self.collectionView numberOfItemsInSection:section] - 1;
        if (lastIndex < 0)
            continue;

        UICollectionViewLayoutAttributes *firstItem = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
        UICollectionViewLayoutAttributes *lastItem = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForRow:lastIndex inSection:section]];

        CGRect frame = CGRectUnion(firstItem.frame, lastItem.frame);
        frame.origin.x -= self.sectionInset.left;
        frame.origin.y -= self.sectionInset.top;

        if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal)
        {
            frame.size.width += self.sectionInset.left + self.sectionInset.right;
            frame.size.height = self.collectionView.frame.size.height;
        }
        else
        {
            frame.size.width = self.collectionView.frame.size.width;
            frame.size.height += self.sectionInset.top + self.sectionInset.bottom;
        }


        UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:decorationViewOfKind withIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
        attributes.zIndex = -1;
        attributes.frame = frame;
        [self.itemAttributes addObject:attributes];
        [self registerNib:[UINib nibWithNibName:decorationViewOfKind bundle:[NSBundle mainBundle]] forDecorationViewOfKind:decorationViewOfKind];
    }
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSMutableArray *attributes = [NSMutableArray arrayWithArray:[super layoutAttributesForElementsInRect:rect]];
    for (UICollectionViewLayoutAttributes *attribute in self.itemAttributes)
    {
        if (!CGRectIntersectsRect(rect, attribute.frame))
            continue;

        [attributes addObject:attribute];
    }

    return attributes;
}

@end

In the field of view of the controller

- (void)viewDidLoad
{
    [super viewDidLoad];
    SectionBackgroundLayout *layout = (id)self.collectionView.collectionViewLayout;
    layout.decorationViewOfKinds = @[@"SectionBackgroundView1", @"SectionBackgroundView2", [NSNull null]];
    ...
}
+1

-(CGRect) rectForSectionAtIndextPath:(NSIndexPath *) indexPath
{
  NSInteger count = [self.collectionView.dataSource collectionView:self.collectionView numberOfItemsInSection:indexPath.section];

UICollectionViewLayoutAttributes *first = [self.collectionView layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:indexPath.section]];
CGFloat startY = first.frame.origin.y;

UICollectionViewLayoutAttributes *last = [self.collectionView layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:(count-1) inSection:indexPath.section]];
CGFloat endY = last.frame.origin.y + last.frame.size.height;

return CGRectMake(0, startY, self.collectionViewContentSize.width, endY-startY);

 }
0

Source: https://habr.com/ru/post/1535689/


All Articles