11

I am trying to imitate what Apple has when showing the search result in the App Store. (reference: http://searchengineland.com/apple-app-search-shows-only-one-result-at-a-time-133818)

It shows like the detailed-application-info in a cards and it is paged. I am stuck at how to make the previous-and-next card shows when one active card in the middle and the scroll view's paging behaviour is still intact.

I have tried using the UICollectionView and set the clipSubviews to NO, hoping that it will show the previous page and the next page, but as soon as the cell goes off-screen, the cell gets hidden (removed from the view hierarchy) and not displayed. I think thats the flyweight pattern of the UICollectionView (the behavior of UICollectionView). Any ideas of what would be possible?

Cheers,

Rendy Pranata

Rpranata
  • 2,010
  • 18
  • 24

2 Answers2

7

The problem: UICollectionView as a subclass of UIScrollView essentially animates its bounds by a stride of bounds.size. Although this could mean that all you had to do is decrease the bounds while keeping the frame bigger, unfortunately UICollectionView will not render any cells outside its current bounds... destroying your preview effect.

The Solution:

  1. Create a UICollectionView with paging set to NO and with the desired frame.
  2. Create UICollectionViewCells that are smaller than the UICollectionView's frame/bounds. At this stage, a part of the next cell should show in the frame. This should be visible before implementing the other steps below.
  3. Add a collectionView.contentInset.left and right (I assume your layout is horizontal) equal to the contentOffsetValue method (as shown below for simplicity) so as to align the first and last cells to the middle.
  4. Create a UICollectionViewFlowLayout which overrides the method that gives the stopping point like so:

Like so:

-(CGFloat)contentOffsetValue
{
    return self.collectionView.bounds.size.width * 0.5f - self.itemSize.width * 0.5f;
}

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{

    static float EscapeVelocity = 0.5f; // otherwise snap back to the middle
    NSArray* layoutAttributesArray = [self layoutAttributesForElementsInRect:self.collectionView.bounds];

    if(layoutAttributesArray.count == 0)
        return proposedContentOffset;

    CGFloat currentBoundsCenterX = self.collectionView.contentOffset.x + self.collectionView.bounds.size.width * 0.5f;


    UICollectionViewLayoutAttributes* candidateNextLayoutAttributes = layoutAttributesArray.firstObject;


    for (UICollectionViewLayoutAttributes* layoutAttributes in layoutAttributesArray)
    {
        if ((layoutAttributes.representedElementCategory != UICollectionElementCategoryCell) ||
            (layoutAttributes == candidateNextLayoutAttributes)) // skip the first comparison
            continue;

        if(velocity.x > EscapeVelocity || velocity.x < -(EscapeVelocity))
        {
            if(velocity.x > EscapeVelocity && layoutAttributes.center.x > candidateNextLayoutAttributes.center.x)
            {

                candidateNextLayoutAttributes = layoutAttributes;
            }

            else if (velocity.x < -(EscapeVelocity) && layoutAttributes.center.x < candidateNextLayoutAttributes.center.x)
            {

                candidateNextLayoutAttributes = layoutAttributes;
            }
        }
        else
        {
            if(fabsf(currentBoundsCenterX - layoutAttributes.center.x) < fabsf(currentBoundsCenterX - candidateNextLayoutAttributes.center.x))
            {

                candidateNextLayoutAttributes = layoutAttributes;
            }
        }   
    }
    return CGPointMake(candidateNextLayoutAttributes.center.x - self.collectionView.bounds.size.width * 0.5f, proposedContentOffset.y);

}
iwasrobbed
  • 46,496
  • 21
  • 150
  • 195
Mike M
  • 4,879
  • 5
  • 38
  • 58
  • This doesn't seem to snap the first and last cells – Jiho Kang Jul 07 '14 at 11:36
  • That is because there is no 'space' for the collection view to navigate. It is outside of the code above. Try setting 'contentInset' on the collection view itself. – Mike M Jul 16 '14 at 20:54
  • It wasnt working for me untill i turned OFF pagination OFF on my collectionview. – i.jameelkhan Oct 17 '14 at 12:41
  • Thanks! I updated the text above. Also, you can have a look at another answer I wrote on the topic: http://stackoverflow.com/questions/20496850/uicollectionview-with-paging-setting-page-width/22696037#22696037 – Mike M Oct 18 '14 at 09:22
  • 1
    Thanks! This is the most correct answer for I've found out there! Perfect! – Dustin Jan 03 '17 at 23:39
0

I just put together a sample project which shows how you could do this. I created a container view which is 100 points wider than the 320 points for the screen. Then I put a UICollectionView into that container. This offsets everything by 50 points on both sides of the screen.

Then there is a content cell which simply has a background and a label so you can visually identify what is happening. On the left and right there are empty cells. In the viewDidLoad method the content inset is set to negative values on the left and right to make the empty cells now scroll into view. You can adjust the inset to your preference.

This mimics the behavior fairly closely. To get the label below, like in the example you can simply check the contentOffset value to determine which cell is in focus. To do that you'd use the UIScrollViewDelegate which is a part of UICollectionView.

https://github.com/brennanMKE/Interfaces/tree/master/ListView

You'll notice this sample project has 2 collection views. One is a normal horizontal flow layout while the other one which has larger cells is the one which mimics the example you mentioned.

Brennan
  • 11,546
  • 16
  • 64
  • 86
  • I simplified the layout so view does not use a container view and does not have to be wider than the screen. https://github.com/brennanMKE/Interfaces/tree/master/ListView – Brennan Aug 02 '13 at 21:59
  • I downloaded the code from the link but I do not see anything like Rpranata is mentioning... Am I misunderstanding the question? – Mike M Mar 20 '14 at 18:25
  • This does no paging. – mxcl Nov 16 '16 at 16:51