I have a custom UICollectionView. It looks good, everything is in place, but as soon as I start scrolling, everything screws up. Images in cells are misplaced, have wrong size and so on.
My custom ViewController
looks like this
@implementation E5BaseDashboardViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.horizontalPadding = 10.0f;
self.verticalPadding = 10.0f;
NSManagedObjectContext *context = [[E5RestKitManager sharedInstance] threadSafeManagedObjectContext];
[context performBlockAndWait:^{
self.collectionViewData = [[E5MenuPointController sharedInstance] rootEntityMenuPointsWithDrawerPosition:E5DrawerPositionCenter andContext:context];
}];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
self.collectionView.backgroundColor = [UIColor colorWithRed:0.965f green:0.961f blue:0.953f alpha:1.00f];
// view is not hidden under navigation bar
if ([self respondsToSelector:@selector(edgesForExtendedLayout)]) {
self.edgesForExtendedLayout = UIRectEdgeNone;
// we need to move collectionView by the size of navigation bar + padding
self.collectionView.contentInset = UIEdgeInsetsMake(0, 0, CGRectGetHeight(self.navigationController.navigationBar.frame) + 2 * self.verticalPadding, 0);
}
[self.collectionView registerClass:[E5DashboardItemCell class] forCellWithReuseIdentifier:cell_identifier];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
[self.view addSubview:self.collectionView];
}
#pragma mark -
#pragma mark E5BaseDashboardViewController Data Source
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section;
{
return [self.collectionViewData count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath;
{
E5DashboardItemCell *cell = [cv dequeueReusableCellWithReuseIdentifier:cell_identifier forIndexPath:indexPath];
E5MenuPoint *menuPoint = (E5MenuPoint *) [self.collectionViewData objectAtIndex:indexPath.row];
[cell configureCellWithMenuPoint: menuPoint];
if ([[E5MenuPointController sharedInstance] isCategoryMenuPoint: menuPoint])
{
[cell.imageView setHidden:YES];
[cell.circleBorder setHidden: YES];
}
else
{
[cell.imageView setHidden: NO];
[cell.circleBorder setHidden: NO];
}
return cell;
}
#pragma mark -
#pragma mark E5BaseDashboardViewController Delegate layout setup
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
E5MenuPoint *menuPoint = (E5MenuPoint *) [self.collectionViewData objectAtIndex:indexPath.row];
if ([[E5MenuPointController sharedInstance] isCategoryMenuPoint: menuPoint])
{
//set header cell size
CGSize cellFrame = CGSizeMake(100, 100);
cellFrame.height = (self.view.frame.size.width - 20) / 4;
cellFrame.width = self.view.frame.size.width - 20;
return cellFrame;
}
else
{
NSNumber *num = [NSNumber numberWithInt:56];
[menuPoint setCounter_notification_total: num];
//set tile cell size
CGSize cellFrame = CGSizeMake(100, 100);
cellFrame.height = (self.view.frame.size.width/2 - 15) * 1.25f;
cellFrame.width = self.view.frame.size.width/2 - 15;
return cellFrame;
}
}
#pragma mark -
#pragma mark E5BaseDashboardViewController Delegate insets, spacing
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
//set cell insets
return UIEdgeInsetsMake(10, 10, 10, 10);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
//set horizontal cell spacing
return self.horizontalPadding;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
//set vertical cell spacing
return self.verticalPadding;
}
#pragma mark -
#pragma mark E5BaseDashboardViewController Delegate selection
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
[[E5MenuPointController sharedInstance] setNotificationCounterTo:0 forMenuPointWithReference:[(E5MenuPoint *)[self.collectionViewData objectAtIndex:indexPath.row] ref]];
[E5ActionHandler performActionOfType:[(E5MenuPoint *)[self.collectionViewData objectAtIndex:indexPath.row] action_type]
name:[(E5MenuPoint *)[self.collectionViewData objectAtIndex:indexPath.row] name]
reference:[(E5MenuPoint *)[self.collectionViewData objectAtIndex:indexPath.row] ref]
targetReference:[(E5MenuPoint *)[self.collectionViewData objectAtIndex:indexPath.row] action_target_ref]
andUrl:[(E5MenuPoint *)[self.collectionViewData objectAtIndex:indexPath.row] action_url]
withStoryboard:self.storyboard
andDrawerController:self.mm_drawerController
backToRoot:YES];
// track the action
if([[(E5MenuPoint *)[self.collectionViewData objectAtIndex:indexPath.row] action_ref] length] > 0)
{
[[E5TrackingController sharedInstance] trackActionWithReference:[(E5MenuPoint *)[self.collectionViewData objectAtIndex:indexPath.row] action_ref]];
}
}
#pragma mark -
#pragma mark dealloc
- (void)dealloc
{
_collectionView.delegate = nil;
_collectionView.dataSource = nil;
}
@end
and custom DashboardItemCell
class looks like this:
#import "E5DashboardItemCell.h"
#import "E5MenuPoint.h"
#import "E5MenuPointController.h"
@implementation E5DashboardItemCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// change to our custom selected background view
self.backgroundColor = [UIColor whiteColor];
self.layer.borderWidth = 1.0f;
self.layer.borderColor = [UIColor colorWithRed:0.925f green:0.925f blue:0.925f alpha:1.00f].CGColor;
_circleBorder = [CAShapeLayer layer];
[_circleBorder setFrame: CGRectMake(30, 20, self.frame.size.width - 60, self.frame.size.width - 60)];
[_circleBorder setPath:[[UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, _circleBorder.frame.size.width, _circleBorder.frame.size.height)] CGPath]];
[_circleBorder setStrokeColor:[[UIColor colorWithRed:0.910f green:0.910f blue:0.898f alpha:1.00f] CGColor]];
[_circleBorder setFillColor:[[UIColor clearColor] CGColor]];
[self.layer addSublayer:self.circleBorder];
CGFloat radius = self.circleBorder.frame.size.width/2;
CGFloat positionNotificationCenter = sqrt(radius * radius/ 2);
_notificationCircle = [CAShapeLayer layer];
[_notificationCircle setFrame:CGRectMake(self.circleBorder.frame.origin.x + radius + positionNotificationCenter - radius/4,
self.circleBorder.frame.origin.y + radius - positionNotificationCenter - radius/4,
radius/2, radius/2)];
[_notificationCircle setPath:[[UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, _notificationCircle.frame.size.width, _notificationCircle.frame.size.height)] CGPath]];
[_notificationCircle setStrokeColor:[[UIColor whiteColor] CGColor]];
[_notificationCircle setFillColor:[[UIColor colorWithRed:0.949f green:0.349f blue:0.196f alpha:1.00f] CGColor]];
[self.layer addSublayer:self.notificationCircle];
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(self.circleBorder.frame.origin.x + self.circleBorder.frame.size.width/2 - self.circleBorder.frame.size.width/5,
self.circleBorder.frame.origin.y + self.circleBorder.frame.size.height/2 - self.circleBorder.frame.size.height/5,
self.circleBorder.frame.size.width/2.5,
self.circleBorder.frame.size.height/2.5)];
[self.layer addSublayer: self.imageView.layer];
_counter = [[UILabel alloc] initWithFrame:CGRectMake(_notificationCircle.frame.origin.x, _notificationCircle.frame.origin.y, _notificationCircle.frame.size.width, _notificationCircle.frame.size.height)];
_counter.textAlignment = NSTextAlignmentCenter;
[_counter setFont:[UIFont boldSystemFontOfSize:15]];
_counter.textColor = [UIColor whiteColor];
[self.layer addSublayer: self.counter.layer];
_textLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
[_textLabel setFont:[UIFont systemFontOfSize:15]];
_textLabel.textAlignment=NSTextAlignmentCenter;
_textLabel.numberOfLines = 0;
_textLabel.lineBreakMode = NSLineBreakByWordWrapping;
_textLabel.textColor = [UIColor colorWithRed:0.392f green:0.392f blue:0.380f alpha:1.00f];
[self.layer addSublayer: self.textLabel.layer];
}
return self;
}
- (void)configureCellWithMenuPoint:(E5MenuPoint *)menuPoint
{
BOOL isCategory = [[E5MenuPointController sharedInstance] isCategoryMenuPoint:menuPoint];
// -- text --
self.textLabel.frame = isCategory ? CGRectMake(10, 5, self.frame.size.width - 20, self.frame.size.height - 10) : CGRectMake(10, self.circleBorder.frame.origin.y + self.circleBorder.frame.size.height + 10, self.frame.size.width - 20 , self.frame.size.height - self.circleBorder.frame.size.height - self.circleBorder.frame.origin.y - 20);
self.textLabel.text = menuPoint.name;
// -- image --
if([menuPoint.image_small length] > 0 | [menuPoint.image_medium length] > 0 | [menuPoint.image_large length] > 0)
{
// show image
if (self.imageView == nil) {
self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(52.5f,42.5f,40,40)];
[self addSubview:self.imageView];
}
// get the most appropriate image size for the display
NSString *imageURLAsString = [NSString string];
if([E5Utils isRetinaDisplay])
{
// retina display image priorities: medium, large, small
if([menuPoint.image_medium length] > 0)
{
imageURLAsString = menuPoint.image_medium;
}
else if([menuPoint.image_large length] > 0)
{
imageURLAsString = menuPoint.image_large;
}
else if([menuPoint.image_small length] > 0)
{
imageURLAsString = menuPoint.image_small;
}
} else {
// non-retina display image priorities: small, medium, large
if([menuPoint.image_small length] > 0)
{
imageURLAsString = menuPoint.image_small;
} else if([menuPoint.image_medium length] > 0)
{
imageURLAsString = menuPoint.image_medium;
} else if([menuPoint.image_large length] > 0)
{
imageURLAsString = menuPoint.image_large;
}
}
if([imageURLAsString length] > 0)
{
[self.imageView setImageWithURL:[NSURL URLWithString:imageURLAsString] placeholderImage:[UIImage imageNamed:@"drawer_item_icon"]];
}
}
else
{
if(self.imageView != nil)
{
// hide imageView
[self.imageView removeFromSuperview];
self.imageView = nil;
}
}
// -- counter --
[self.counter setText:[NSString stringWithFormat:@"%@", menuPoint.counter_notification_total]];
if (menuPoint.counter_notification_total.integerValue < 9)
{
[_counter setFont:[UIFont boldSystemFontOfSize:13]];
}
else if (menuPoint.counter_notification_total.integerValue > 9 && menuPoint.counter_notification_total.integerValue < 99)
{
[_counter setFont:[UIFont boldSystemFontOfSize:10]];
}
else if (menuPoint.counter_notification_total.integerValue > 99)
{
[_counter setFont:[UIFont boldSystemFontOfSize:7]];
}
BOOL showCounter = FEATURE_MENUITEM_COUNTERS && menuPoint.countWithPermanent > 0;
if (!isCategory && showCounter) {
[self.counter setHidden:NO];
[self.notificationCircle setHidden: NO];
} else {
[self.counter setHidden:YES];
[self.notificationCircle setHidden: YES];
}
}
@end
I guess it has something to do with reusing of the cells, but I just cannot figure out what. It is driving me crazy. Does anyone please have any idea what could be wrong?
Thank you very much
Got it working. You have to have separate identifiers for various types of cells. Since I was using only one identifier, but had 2 types of cells, my frames got messed up by reusing cells of just one type.