在选择时为UICollectionView单元设置动画

时间:2013-02-04 19:38:05

标签: ios uicollectionview uicollectionviewcell uicollectionviewlayout

我在UICollectionView中有一个基本网格。这是使用UICollectionViewDelegateFlowLayout的简单2列多行布局。选择单元格后,我想调暗背景,将单元格浮动到屏幕中心,然后根据所选单元格建立工作流程。我对UICollectionViews还不熟悉,我不确定最好的方法。

在选择单元格时,我应该有UICollectionView的自定义布局吗?

或者是否有一种方法可以为所选单元设置动画而无需创建新布局

如果有人能让我朝着正确的方向前进,我想我会很好地研究如何执行它。

2 个答案:

答案 0 :(得分:12)

在尝试了几个(而不是hacky)解决方案后,我通过编写自己的UICollectionView布局解决了这个问题。我尝试过以前的解决方案:

  • UICollectionView上方添加一个自定义UIView,并尝试通过覆盖原始单元格,使背景变暗以及为新UIView设置动画来伪造原始单元格
  • 为单元设置动画而不创建全新的布局

我试图避免它,但是在我编码之后,它比我原先想象的要痛苦得多。

这是我的代码,对于任何感兴趣的人:

<强>·H

@interface FMStackedLayout : UICollectionViewLayout

@property(nonatomic,assign) CGPoint     center;
@property(nonatomic,assign) NSInteger   cellCount;

-(id)initWithSelectedCellIndexPath:(NSIndexPath *)indexPath;

@end

<强>的.m:

#define ITEM_WIDTH  128.0f
#define ITEM_HEIGHT 180.0f

static NSUInteger       const RotationCount         = 32;
static NSUInteger       const RotationStride        = 3;
static NSUInteger       const PhotoCellBaseZIndex   = 100;

@interface FMStackedLayout ()

@property(strong,nonatomic) NSArray     *rotations;
@property(strong,nonatomic) NSIndexPath *selectedIndexPath;

@end

@implementation FMStackedLayout

#pragma mark - Lifecycle
-(id)initWithSelectedCellIndexPath:(NSIndexPath *)indexPath{
    self = [super init];
    if (self) {
        self.selectedIndexPath = indexPath;
        [self setup];
    }
    return self;
}

-(id)initWithCoder:(NSCoder *)aDecoder{
    self = [super init];
    if (self){
        [self setup];
    }
    return self;
}

-(void)setup{
    NSMutableArray *rotations = [NSMutableArray arrayWithCapacity:RotationCount];
    CGFloat percentage = 0.0f;

    for (NSUInteger i = 0; i < RotationCount; i++) {
        // Ensure that each angle is different enough to be seen
        CGFloat newPercentage = 0.0f;
        do {
            newPercentage = ((CGFloat)(arc4random() % 220) - 110) * 0.0001f;
        } while (fabsf(percentage - newPercentage) < 0.006);

        percentage = newPercentage;

        CGFloat angle = 2 * M_PI * (1.0f + percentage);
        CATransform3D transform = CATransform3DMakeRotation(angle, 0.0f, 0.0f, 1.0f);
        [rotations addObject:[NSValue valueWithCATransform3D:transform]];
    }

    self.rotations = rotations;
}

#pragma mark - Layout
-(void)prepareLayout{
    [super prepareLayout];

    CGSize size = self.collectionView.frame.size;
    self.cellCount = [self.collectionView numberOfItemsInSection:0];
    self.center = CGPointMake(size.width / 2.0, size.height / 2.0);
}

-(CGSize)collectionViewContentSize{
    return self.collectionView.frame.size;
}

-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

    attributes.size = CGSizeMake(ITEM_WIDTH, ITEM_HEIGHT);
    attributes.center = self.center;
    if (indexPath.item == self.selectedIndexPath.item) {
        attributes.zIndex = 100;
    }else{
        attributes.transform3D = [self transformForPersonViewAtIndex:indexPath];
    }

    return attributes;
}

-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
    NSMutableArray *attributes = [NSMutableArray array];
    for (NSInteger i = 0; i < self.cellCount; i++) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i
                                                     inSection:0];
        [attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
    }
    return attributes;
}

#pragma mark - Private
-(CATransform3D)transformForPersonViewAtIndex:(NSIndexPath *)indexPath{
    NSInteger offset = (indexPath.section * RotationStride + indexPath.item);
    return [self.rotations[offset % RotationCount] CATransform3DValue];
}

@end

然后,在您的UICollectionView上,您调用

MyLayout *stackedLayout = [[MyLayout alloc] initWithSelectedCellIndexPath:indexPath];
[stackedLayout invalidateLayout];
[self.collectionView setCollectionViewLayout:stackedLayout
                                    animated:YES];

单元格之间的动画将由自定义布局处理。

答案 1 :(得分:6)

似乎是一个多部分的问题,所以我会回答其中的一部分。

  1. UICollectionviewCells 不会在突出显示选择上自动调整 。它只会告诉您何时突出显示或选择单元格,但有一个例外:
  2.   

    在大多数情况下,集合视图仅修改其属性   一个单元格,表示它已被选中或突出显示;它不是   改变细胞的视觉外观,但有一个例外。如果一个   单元格的selectedBackgroundView属性包含有效视图   集合视图显示单元格突出显示时的视图或   地选择。

    否则,您必须手动执行 visual 突出显示。通常通过使用以下一种或多种方法调整整个单元格的.alpha属性,或者在单元格本身中交换背景.image的{​​{1}}属性,这些方法是可访问的在<UICollectionViewDelegate>协议中:

    UIImageView

    至于你提出的其他问题,我希望能提供更多帮助,但我对自定义视图动画不太熟悉。