Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a background image to UICollectionView that will scroll and zoom will cells

I'm building a mosaic view using UICollectionView.

I have subclassed UICollectionViewFlowLayout to layout a fixed grid that can be scrolled both horizontally and vertically. I have also attached a UIPinchGestureRecognizer so the collection can scaled/zoomed.

Each cell in the collection contains a UIImage with some transparency. I want to add a background image that will scroll and zoom with the cells.

I've attempted a number of different solutions.

  • setting the background color of the UICollectionView using colorWithPatternImage. (does not scroll/resize with content)
  • setting a background image view on each cell to the relevant cropped portion of the background image. (uses far too much memory)

I've been looking into Supplementary and Decoration Views but struggling to get my head around it. I think I need to use Supplementary views as the image used in the background will change depending on the datasource.

What I don't understand is how I can register just one Supplementary View to span the width and height of the whole collectionview. They seem to be tied to an indexPath i.e each cell.

like image 230
th3hamburgler Avatar asked Jan 16 '14 12:01

th3hamburgler


People also ask

How CollectionView works?

The collection view presents items onscreen using a cell, which is an instance of the UICollectionViewCell class that your data source configures and provides. In addition to its cells, a collection view can present data using other types of views.

What is a CollectionView?

A collection view manages an ordered set of content, such as the grid of photos in the Photos app, and presents it visually. Collection views are a collaboration between many different objects, including: Cells. A cell provides the visual representation for each piece of your content. Layouts.

How to create a collection view?

Select the Main storyboard from the file browser. Add a CollectionView by pressing command shift L to open the storyboard widget window. Drag the collectionView onto the main view controller. Add constraints to the UICollectionView widget to ensure that the widget fills the screen on all devices.


1 Answers

Don't know if you found an answer...!

You're on the right track with wanting to use supplementary views. The index path of the supplementary view isn't tied to a cell, it has its own index path.

Then in your subclass of UICollectionViewFlowLayout you need to subclass a few methods. The docs are pretty good!

In the layoutAttributesForElementsInRect: method you'll need to call super and then add another set of layout attributes for your supplementary view.

Then in the layoutAttributesForSupplementaryViewOfKind:atIndexPath: method you set the size of the returned attributes to the size of the collection view content so the image fills all the content, and not just the frame. You also probably want to set the z-order to, to make sure it's behind the cells. See the docs for UICollectionViewLayoutAttributes

@implementation CustomFlowLayout

    -(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
    {
        NSMutableArray *attributes = [[super layoutAttributesForElementsInRect:rect] mutableCopy];

        // Use your own index path and kind here
        UICollectionViewLayoutAttributes *backgroundLayoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:@"background" atIndexPath:[NSIndexPath indexPathWithItem:0 inSection:0]];

        [attributes addObject:backgroundLayoutAttributes];

        return [attributes copy];
    }

    -(UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath

        if ([kind isEqualToString:@"background"]) {
            UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:kind withIndexPath:indexPath];
            attrs.size = [self collectionViewContentSize];
            attrs.zIndex = -10;
            return attrs;
        } else {
            return [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath];
        }
    }

@end

In your collection view data source you need this method: collectionView:viewForSupplementaryElementOfKind:atIndexPath:

-(void)viewDidLoad
{
    [super viewDidLoad];

    // Setup your collection view
    UICollectionView *collectionView = [UICollectionView initWithFrame:self.view.bounds collectionViewLayout:[CustomFlowLayout new]];
    [collectionView registerClass:[BackgroundReusableView class] forSupplementaryViewOfKind:@"background" withReuseIdentifier:@"backgroundView"];
}

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
    if ([kind isEqualToString:@"background"]) {
        BackgroundReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"backgroundView" forIndexPath:indexPath];

        // Set extra info

        return view;
    } else {
        // Shouldn't be called
        return nil;
    }
}

Hopefully all that should get you on the right track :)

like image 67
Rich Avatar answered Sep 23 '22 12:09

Rich