简体   繁体   中英

Cell elements get misplaced when scrolling - CollectionView

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM