Search code examples
iosobjective-cuicollectionviewuicollectionviewlayout

Collapsing UICollectionView


I'm having a fight with UICollectionView to adopt it to my needs.

I'm trying to build a collapsing tag cloud. All elements can dynamically change size based on text inside.

When collection is displayed, I would like to display only first row and hide rest of content. If there is more content than just for one row I want to show a button as a last item in first row - after selecting it, I will change collection size to fit it's content.

First step:

first step

After click:

second step

I was able to achieve desired effect with this code:

- (void) updateFrame
{
    if(self.showFull)
    {
        self.showMoreButton.hidden = YES;
        self.bottomConstrain.constant = 0;
        self.frame = CGRectMake(0, 0, self.collectionView.frame.size.width, self.collectionView.contentSize.height);
    }
    else
    {
        self.showMoreButton.hidden = NO;
        self.bottomConstrain.constant = self.originalConstrainValue;
        self.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
    }
}

But button in my case is placed completely outside the collection:

screen

I'm hitting my head against a brick wall how to make this button to be a part of collection view. It's the first time I'm playing with UICollectionView and UICollectionViewFlowLayout and it's too complex for me still to understand where would be best spot to put it.

  1. One idea I had was to play a button over UICollectionView and position it at the end of first row - but I don't know how to get first row size from collection. With this approach it will be problematic also to cover last item in a row.

  2. I think the best will be to put this element as a UICollectionViewCell, but I have no idea how to approach that - how to predict where it will placed and how to hide it later.

Any ideas will be highly appreciated. Current template project is here:

https://www.zipshare.com/download/eyJhcmNoaXZlSWQiOiJjNTg2MGFkNC1mYWYxLTRlMzItOTA1YS1hMWFjOGFkMjMzYjUiLCJlbWFpbCI6Imdya3J1a293c2tpQGdtYWlsLmNvbSJ9


Solution

  • I've managed to achieve what I wanted with this code (thanks for atreat for suggestion).

    I'm estimating which element won't fit in first row, and pushing "More" tag into tags array. There is some logic also to make sure that More button will fit after last element in this row, if not it's pushed instead of this element. Maybe some will find it usefull.

        UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout*)self.collectionView.collectionViewLayout;
            CGFloat collectionWidth = self.frame.size.width;
            CGFloat lastFittingItemRight = 0.0f;
            CGFloat spacingBetweenElements = flowLayout.minimumInteritemSpacing;
            CGFloat sectionInsetLeft = flowLayout.sectionInset.left;
            CGFloat sectionInsetRight = flowLayout.sectionInset.right;
    
            CGFloat rightEdge = sectionInsetLeft;
    
            for (int i = 0; i < [self collectionView:self.collectionView numberOfItemsInSection:0]; i++)
            {
                CGSize elementSize = [self collectionView:self.collectionView layout:flowLayout sizeForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
                CGFloat elementWidth = elementSize.width;
                rightEdge += elementWidth;
    
                if(rightEdge > collectionWidth - sectionInsetRight)
                {
                    self.moreButtonIndexPath = [NSIndexPath indexPathForItem:i inSection:0];
                    break;
                }
    
                lastFittingItemRight = rightEdge;
                rightEdge += spacingBetweenElements;
            }
    
            if(self.moreButtonIndexPath)
            {
                NSString* showMoreText = @"More";
                CGSize moreButtonSize = [self sizeForTagWithText:showMoreText];
                CGFloat rightEdgeMoreButton = lastFittingItemRight + spacingBetweenElements + moreButtonSize.width;
    
                NSInteger moreButtonIndex = self.moreButtonIndexPath.row;
                if(rightEdgeMoreButton > collectionWidth - sectionInsetRight)
                {
                    moreButtonIndex = moreButtonIndex-1;
                }
    
                [self.tags insertObject:showMoreText atIndex:moreButtonIndex];
            }