2013-11-04 19 views
5

Evernote'un iOS 7'de kullandığı esnek koleksiyon görünümünü yeniden oluşturmaya çalışıyorum ve çalışmaya gerçekten çok yakınım. İçerik ofseti y değeri koleksiyon görünüm sınırları dışında olduğunda düzen özelliği dönüşümlerini değiştiren özel bir koleksiyon görünümü akış düzeni oluşturmayı başardım. LayoutAttributesForElementsInRect yöntemindeki düzen niteliklerini değiştiriyorum ve kaydırma görünümünün altına vurduğunuzda alt hücrelerin kaybolacak olması dışında beklendiği gibi davranıyor. İçeriği daha fazla çekerseniz, daha fazla hücre kaybolabilir. Sanırım hücreler temelde kısıldı. En tepede olmaz ve her iki yerde de aynı davranışı görmeyi beklerdim. Akış düzeni uygulamam şu anki gibi görünüyor.iOS 7 üzerinde Evernote gibi bir UICollectionView oluşturma

@implementation CNStretchyCollectionViewFlowLayout 
{ 
    BOOL  _transformsNeedReset; 
    CGFloat  _scrollResistanceDenominator; 
} 

- (id)init 
{ 
    self = [super init]; 
    if (self) 
    { 
     // Set up the flow layout parameters 
     self.minimumInteritemSpacing = 10; 
     self.minimumLineSpacing = 10; 
     self.itemSize = CGSizeMake(320, 44); 
     self.sectionInset = UIEdgeInsetsMake(10, 0, 10, 0); 

     // Set up ivars 
     _transformsNeedReset = NO; 
     _scrollResistanceDenominator = 800.0f; 
    } 

    return self; 
} 

- (void)prepareLayout 
{ 
    [super prepareLayout]; 
} 

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 
{ 
    // Set up the default attributes using the parent implementation 
    NSArray *items = [super layoutAttributesForElementsInRect:rect]; 

    // Compute whether we need to adjust the transforms on the cells 
    CGFloat collectionViewHeight = self.collectionViewContentSize.height; 
    CGFloat topOffset = 0.0f; 
    CGFloat bottomOffset = collectionViewHeight - self.collectionView.frame.size.height; 
    CGFloat yPosition = self.collectionView.contentOffset.y; 

    // Update the transforms if necessary 
    if (yPosition < topOffset) 
    { 
     // Compute the stretch delta 
     CGFloat stretchDelta = topOffset - yPosition; 
     NSLog(@"Stretching Top by: %f", stretchDelta); 

     // Iterate through all the visible items for the new bounds and update the transform 
     for (UICollectionViewLayoutAttributes *item in items) 
     { 
      CGFloat distanceFromTop = item.center.y; 
      CGFloat scrollResistance = distanceFromTop/800.0f; 
      item.transform = CGAffineTransformMakeTranslation(0, -stretchDelta + (stretchDelta * scrollResistance)); 
     } 

     // Update the ivar for requiring a reset 
     _transformsNeedReset = YES; 
    } 
    else if (yPosition > bottomOffset) 
    { 
     // Compute the stretch delta 
     CGFloat stretchDelta = yPosition - bottomOffset; 
     NSLog(@"Stretching bottom by: %f", stretchDelta); 

     // Iterate through all the visible items for the new bounds and update the transform 
     for (UICollectionViewLayoutAttributes *item in items) 
     { 
      CGFloat distanceFromBottom = collectionViewHeight - item.center.y; 
      CGFloat scrollResistance = distanceFromBottom/800.0f; 
      item.transform = CGAffineTransformMakeTranslation(0, stretchDelta + (-stretchDelta * scrollResistance)); 
     } 

     // Update the ivar for requiring a reset 
     _transformsNeedReset = YES; 
    } 
    else if (_transformsNeedReset) 
    { 
     NSLog(@"Resetting transforms"); 
     _transformsNeedReset = NO; 
     for (UICollectionViewLayoutAttributes *item in items) 
      item.transform = CGAffineTransformIdentity; 
    } 

    return items; 
} 

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds 
{ 
    // Compute whether we need to adjust the transforms on the cells 
    CGFloat collectionViewHeight = self.collectionViewContentSize.height; 
    CGFloat topOffset = 0.0f; 
    CGFloat bottomOffset = collectionViewHeight - self.collectionView.frame.size.height; 
    CGFloat yPosition = self.collectionView.contentOffset.y; 

    // Handle cases where the layout needs to be rebuilt 
    if (yPosition < topOffset) 
     return YES; 
    else if (yPosition > bottomOffset) 
     return YES; 
    else if (_transformsNeedReset) 
     return YES; 

    return NO; 
} 

@end 

Ayrıca, kullanıcıların denemesi için projeyi sıkıştırdım. Özel koleksiyon görünümü düzenleri oluşturmak için oldukça yeni olduğum için herhangi bir yardım büyük takdir edilecektir. İşte buna link:

https://dl.dropboxusercontent.com/u/2975688/StackOverflow/stretchy_collection_view.zip

herkese teşekkürler!

+0

Kodunuz, simülatörde beklendiği gibi çalışır. Kırpılmış hücre yok. – Mundi

+0

Sadece test ettim ve iPhone Retina (3.5 inç) simülatörde iyi çalışıyor gibi görünüyor, ancak sorun iPhone Retina (4 inç) simülatörde gerçekleşiyor. – cnoon

cevap

2

Sorunu çözebildim. IOS'ta gerçekten bir hata olup olmadığından emin değilim, ancak sorun, hücrelerin gerçekten de koleksiyon görünümünün içerik görünümü dışında çevrilmeleriydi. Hücre yeterince çevrildikten sonra, kısaltılırdı. Retina dışı görüntüler için simülatörde bunun gerçekleşmediğini ilginç buluyorum ama retina görüntüleriyle birlikte bunun aslında bir hata olabileceğini düşünüyorum.

Bunun için bir geçici çözüm, collectionViewContentSize yöntemini geçersiz kılarak koleksiyon görünümünün en üstüne ve altına dolgu eklemektir. Bunu yaptıktan sonra, üstüne dolgu eklerseniz, hücreler için düzen niteliklerini de ayarlamanız gerekir, böylece bunlar uygun konumdadır. Son adım, dolguyu ayarlamak için contentInset'i koleksiyon görünümüne ayarlamaktır. Kaydırma göstergesi insets'lerini, iyi oldukları için yalnız bırakın. Son koleksiyon görünümü denetleyicimin ve özel akış düzenimin uygulaması.

CNStretchyCollectionViewController.m

@implementation CNStretchyCollectionViewController 

static NSString *CellIdentifier = @"Cell"; 

- (void)viewDidLoad 
{ 
    // Register the cell 
    [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:CellIdentifier]; 

    // Tweak out the content insets 
    CNStretchyCollectionViewFlowLayout *layout = (CNStretchyCollectionViewFlowLayout *) self.collectionViewLayout; 
    self.collectionView.contentInset = layout.bufferedContentInsets; 

    // Set the delegate for the collection view 
    self.collectionView.delegate = self; 
    self.collectionView.clipsToBounds = NO; 

    // Customize the appearance of the collection view 
    self.collectionView.backgroundColor = [UIColor whiteColor]; 
    self.collectionView.indicatorStyle = UIScrollViewIndicatorStyleDefault; 
} 

#pragma mark - UICollectionViewDataSource Methods 

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

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath]; 
    if ([indexPath row] % 2 == 0) 
     cell.backgroundColor = [UIColor orangeColor]; 
    else 
     cell.backgroundColor = [UIColor blueColor]; 

    return cell; 
} 

@end 

CNStretchyCollectionViewFlowLayout.m

@interface CNStretchyCollectionViewFlowLayout() 

- (CGSize)collectionViewContentSizeWithoutOverflow; 

@end 

#pragma mark - 

@implementation CNStretchyCollectionViewFlowLayout 
{ 
    BOOL   _transformsNeedReset; 
    CGFloat   _scrollResistanceDenominator; 
    UIEdgeInsets _contentOverflowPadding; 
} 

- (id)init 
{ 
    self = [super init]; 
    if (self) 
    { 
     // Set up the flow layout parameters 
     self.minimumInteritemSpacing = 10; 
     self.minimumLineSpacing = 10; 
     self.itemSize = CGSizeMake(320, 44); 
     self.sectionInset = UIEdgeInsetsMake(10, 0, 10, 0); 

     // Set up ivars 
     _transformsNeedReset = NO; 
     _scrollResistanceDenominator = 800.0f; 
     _contentOverflowPadding = UIEdgeInsetsMake(100.0f, 0.0f, 100.0f, 0.0f); 
     _bufferedContentInsets = _contentOverflowPadding; 
     _bufferedContentInsets.top *= -1; 
     _bufferedContentInsets.bottom *= -1; 
    } 

    return self; 
} 

- (void)prepareLayout 
{ 
    [super prepareLayout]; 
} 

- (CGSize)collectionViewContentSize 
{ 
    CGSize contentSize = [super collectionViewContentSize]; 
    contentSize.height += _contentOverflowPadding.top + _contentOverflowPadding.bottom; 
    return contentSize; 
} 

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 
{ 
    // Set up the default attributes using the parent implementation (need to adjust the rect to account for buffer spacing) 
    rect = UIEdgeInsetsInsetRect(rect, _bufferedContentInsets); 
    NSArray *items = [super layoutAttributesForElementsInRect:rect]; 

    // Shift all the items down due to the content overflow padding 
    for (UICollectionViewLayoutAttributes *item in items) 
    { 
     CGPoint center = item.center; 
     center.y += _contentOverflowPadding.top; 
     item.center = center; 
    } 

    // Compute whether we need to adjust the transforms on the cells 
    CGFloat collectionViewHeight = [self collectionViewContentSizeWithoutOverflow].height; 
    CGFloat topOffset = _contentOverflowPadding.top; 
    CGFloat bottomOffset = collectionViewHeight - self.collectionView.frame.size.height + _contentOverflowPadding.top; 
    CGFloat yPosition = self.collectionView.contentOffset.y; 

    // Update the transforms if necessary 
    if (yPosition < topOffset) 
    { 
     // Compute the stretch delta 
     CGFloat stretchDelta = topOffset - yPosition; 
     NSLog(@"Stretching Top by: %f", stretchDelta); 

     // Iterate through all the visible items for the new bounds and update the transform 
     for (UICollectionViewLayoutAttributes *item in items) 
     { 
      CGFloat distanceFromTop = item.center.y - _contentOverflowPadding.top; 
      CGFloat scrollResistance = distanceFromTop/_scrollResistanceDenominator; 
      item.transform = CGAffineTransformMakeTranslation(0, -stretchDelta + (stretchDelta * scrollResistance)); 
     } 

     // Update the ivar for requiring a reset 
     _transformsNeedReset = YES; 
    } 
    else if (yPosition > bottomOffset) 
    { 
     // Compute the stretch delta 
     CGFloat stretchDelta = yPosition - bottomOffset; 
     NSLog(@"Stretching bottom by: %f", stretchDelta); 

     // Iterate through all the visible items for the new bounds and update the transform 
     for (UICollectionViewLayoutAttributes *item in items) 
     { 
      CGFloat distanceFromBottom = collectionViewHeight + _contentOverflowPadding.top - item.center.y; 
      CGFloat scrollResistance = distanceFromBottom/_scrollResistanceDenominator; 
      item.transform = CGAffineTransformMakeTranslation(0, stretchDelta + (-stretchDelta * scrollResistance)); 
     } 

     // Update the ivar for requiring a reset 
     _transformsNeedReset = YES; 
    } 
    else if (_transformsNeedReset) 
    { 
     NSLog(@"Resetting transforms"); 
     _transformsNeedReset = NO; 
     for (UICollectionViewLayoutAttributes *item in items) 
      item.transform = CGAffineTransformIdentity; 
    } 

    return items; 
} 

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds 
{ 
    return YES; 
} 

#pragma mark - Private Methods 

- (CGSize)collectionViewContentSizeWithoutOverflow 
{ 
    return [super collectionViewContentSize]; 
} 

@end 

CNStretchyCollectionViewFlowLayout.h

@interface CNStretchyCollectionViewFlowLayout : UICollectionViewFlowLayout 

@property (assign, nonatomic) UIEdgeInsets bufferedContentInsets; 

@end 

Aslında bunu Github'a yapacağım ve bu projeye bir kez daha bağlayacağım. Herkese tekrar teşekkürler!

+0

İşte Github projesi [link] (https://github.com/cnoon/Stretchy-Collection-View) – cnoon

+0

Harika :) Hücrelerdeki bu harika etkiyi nasıl kullandığını biliyor musunuz? hücre genişler ve diğerleri "uzaklaşır"? – Macistador