Search code examples
objective-cios6

iOS 6.0: UICollectionView doesn't respect clipsToBounds with pagingEnabled


Background

I am implementing a UICollectionView (for the first time) in an effort to achieve a paged horizontal scroll view of tiles. I'd like each tile to show in the center of the frame with it's sister tiles partially visible to the left and right (something like the page selector in the Safari app). I'm interested in using the UICollectionView to take advantage of built-in cell dequeueing and would rather not use a rotated UITableView.

Issue

The issue I'm finding is that when using pagingEnabled = YES and clipsToBounds = NO, the UICollectionView removes cells outside the collectionView frame (they're not in the visibleCells array) as soon as paging is complete. Can anyone provide advice on how to achieve the effect of displaying previews of the sister tiles while maintaining this basic setup? Or am I approaching this incorrectly?

Screenshots

start start scrolling scrolling end end

The scrolling screen is exactly correct. But in the start and end shots I want there to be green visible in the blue margins.

Here's what's in my AppDelegate.m (credit to tutsplus.com for the basic setup here):

#import "AppDelegate.h"

@interface ViewController : UICollectionViewController
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"ID"];
    [self.view setBackgroundColor:[UIColor blueColor]];
    // pad the collection view by 20 px
    UIEdgeInsets padding = UIEdgeInsetsMake(20.0, 20.0, 20.0, 20.0);
    [self.collectionView setFrame:UIEdgeInsetsInsetRect(self.view.frame, padding)];
    // set pagingEnabled and clipsToBounds off
    [self.collectionView setPagingEnabled:YES];
    [self.collectionView setClipsToBounds:NO];
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return 5;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ID" forIndexPath:indexPath];
    UILabel *label = [[UILabel alloc] initWithFrame:cell.bounds];
    label.textAlignment = NSTextAlignmentCenter;
    label.text = [NSString stringWithFormat:@"%d", indexPath.row];
    [label setBackgroundColor:[UIColor greenColor]];
    [cell.contentView addSubview:label];
    return cell;
}
@end

@implementation AppDelegate
{
    ViewController *vc;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // setup the UICollectionViewFlowLayout
    UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
    layout.itemSize = CGSizeMake(280, 280);
    layout.minimumInteritemSpacing = 0;
    layout.minimumLineSpacing = 0;
    layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    // add a custom UICollectionViewController to the window
    vc = [[ViewController alloc] initWithCollectionViewLayout:layout];
    self.window.rootViewController = vc;
    self.window.backgroundColor = [UIColor yellowColor];
    [self.window makeKeyAndVisible];
    return YES;
}
@end

Solution

  • Turns out the solution to this was actually quite simple. I just needed to overlap the UICollectionViewCell cells by enough pixels to have them still show within the collectionView's frame after the paged scrolling finishes. The relevent code was

    layout.itemSize = CGSizeMake(300, 300);
    layout.minimumLineSpacing = -20.0;
    

    And I subclassed the UICollectionViewFlowLayout and overrode the (CGSize)collectionViewContentSize method to return the non-overlapped size of the cells.