14

我在UICollectionView中有一個基本網格。這是一個簡單的2列,使用UICollectionViewDelegateFlowLayout的多行佈局。選擇單元格時,我想調暗背景,將單元格浮動到屏幕中央,然後根據所選單元格創建工作流程。我對UICollectionViews相當陌生,我不確定最好的解決方法。將動畫UICollectionView單元格選中

當我選擇一個單元格時,我應該有一個UICollectionView的自定義佈局嗎?

還是有辦法,我可以動畫顯示選中的單元格,而無需創建新的佈局

如果任何人都可以只讓我去上了正確的方向,我想我會是很好的研究如何執行它。

回答

12

在嘗試了幾個(而且很冒險的)解決方案後,我通過編寫我自己的UICollectionView佈局來解決這個問題。以前的解決方案我嘗試:

  • 添加自定義的UIView上層建築的UICollectionView並試圖僞造原始細胞通過覆蓋它,調光背景,動畫,新的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]; 

單元格之間的動畫將由自定義佈局處理。

+3

這不是一個答案。看起來你有答案,但不想分享。 – Fiveagle

+1

@Mark Struzinski你能分享一下你的解決方案嗎? –

+0

這是一段相當長的代碼,但我並沒有因爲任何特殊原因而退縮。我已經將其發佈給任何感興趣的人。不知道爲什麼在這裏有downvotes。最終解決方案使用了Apple文檔中詳細記錄的方法:http://developer.apple.com/library/ios/#documentation/uikit/reference/UICollectionViewLayout_class/Reference/Reference.html。我一直在試圖避免它,因爲它的工作量很大。 –

6

似乎是一個多部分問題,所以我會回答它的一部分。

  1. UICollectionviewCells不會自動對亮點選擇調整。它只會告訴你,當細胞被突出顯示或選擇,但有一個例外:

在大多數情況下,集合視圖修改的 細胞只有屬性,以表明它已被選中或突出顯示;它不會 更改您的細胞的視覺外觀,只有一個例外。如果 單元的selectedBackgroundView屬性包含有效視圖,則 集合視圖將顯示單元格高亮顯示時的視圖或 選定的視圖。

否則,您必須手動高亮顯示視覺。通常通過使用以下方法,它們是<UICollectionViewDelegate>議定書以無障礙的一個或多個調整任一.alpha屬性的整個小區的,或換出在細胞本身背景UIImageView.image屬性:

collectionView:didDeselectItemAtIndexPath: 
collectionView:didHighlightItemAtIndexPath: 
collectionView:didSelectItemAtIndexPath: 
collectionView:didUnhighlightItemAtIndexPath: 
collectionView:shouldDeselectItemAtIndexPath: 
collectionView:shouldHighlightItemAtIndexPath: 
collectionView:shouldSelectItemAtIndexPath: 

至於你的問題的其餘部分,我希望我可以有更多的幫助,但我不熟悉自定義視圖動畫。

+0

嗨。我已經嘗試從collectionView:didSelectItemAtIndexPath:進行動畫處理。但是,根據這個問題,我想實際上將單元格移動到屏幕的中心以專注於它。我想知道如果這並不意味着我應該使用模式視圖控制器,並做一些事情,讓它出現單元格動畫。 –