2

I am using UICollectionView in such a way that collection view cell will be in centre of the screen and left and right cells are partially visible. Infect, UICollectionView width is equal to screen width and cell width is lesser so that left and right cells should partially visible. For enabling pagination, I had implement custom code that sets the centre cell in centre of the screen. Now its creating some issues; I want to get any default way to avoid custom implementation that causing the issue.

I want to enable pagination in such a way that I can achieve described behaviour in following image.

If I disable custom implementation and enable default pagination then two cells are partially shown but its not expected behaviour as i want.

enter image description here

Thanks

msmq
  • 1,298
  • 16
  • 28

1 Answers1

2

As far as I know, you can't do this by "default", you need to customise your collectionView. The way I achieved this is by subclassing the collectionView's flow layout and implementing the following method like this:

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
    CGFloat offSetAdjustment = MAXFLOAT;
    CGFloat horizontalCenter = (CGFloat) (proposedContentOffset.x + (self.collectionView.bounds.size.width / 2.0));

    CGRect targetRect = CGRectMake(proposedContentOffset.x, 0.0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);

    NSArray *array = [self layoutAttributesForElementsInRect:targetRect];

    UICollectionViewLayoutAttributes *currentAttributes;

    for (UICollectionViewLayoutAttributes *layoutAttributes in array)
    {
        if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell)
        {
            CGFloat itemHorizontalCenter = layoutAttributes.center.x;
            if (ABS(itemHorizontalCenter - horizontalCenter) < ABS(offSetAdjustment))
            {
                currentAttributes   = layoutAttributes;
                offSetAdjustment    = itemHorizontalCenter - horizontalCenter;
            }
        }
    }

    CGFloat nextOffset          = proposedContentOffset.x + offSetAdjustment;

    proposedContentOffset.x     = nextOffset;
    CGFloat deltaX              = proposedContentOffset.x - self.collectionView.contentOffset.x;
    CGFloat velX                = velocity.x;

    // detection form  gist.github.com/rkeniger/7687301
    // based on http://stackoverflow.com/a/14291208/740949
    if(deltaX == 0.0 || velX == 0 || (velX > 0.0 && deltaX > 0.0) || (velX < 0.0 && deltaX < 0.0)) {

    } else if(velocity.x > 0.0) {
        for (UICollectionViewLayoutAttributes *layoutAttributes in array)
        {
            if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell)
            {
                CGFloat itemHorizontalCenter = layoutAttributes.center.x;
                if (itemHorizontalCenter > proposedContentOffset.x) {
                    proposedContentOffset.x = nextOffset + (currentAttributes.frame.size.width / 2) + (layoutAttributes.frame.size.width / 2);
                    break;
                }
            }
        }
    } else if(velocity.x < 0.0) {
        for (UICollectionViewLayoutAttributes *layoutAttributes in array)
        {
            if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell)
            {
                CGFloat itemHorizontalCenter = layoutAttributes.center.x;
                if (itemHorizontalCenter > proposedContentOffset.x) {
                    proposedContentOffset.x = nextOffset - ((currentAttributes.frame.size.width / 2) + (layoutAttributes.frame.size.width / 2));
                    break;
                }
            }
        }
    }

    proposedContentOffset.y = 0.0;

    return proposedContentOffset;
}

(This piece of code is inspired heavily from something else I found here on SO, but I can't find the reference now).

In my case, the collection view isn't paginated, but this method makes it behave like it is.

Also, if you want to make the first cell of the collection view to start at the center of the screen (and same for the last one), you will have to override this method in the UICollectionViewDelegateFlowLayout

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    CGFloat leftInset = (self.view.bounds.size.width - CELL_WIDTH) / 2;    // CELL_WIDTH is the width of your cell
    return UIEdgeInsetsMake(0, leftInset, 0, leftInset);
}

This method assumes that the collectionView is as wide as the screen. If this is not the case for you, adapt it to your needs by computing the left and right insets for the collectionView.