2013-11-04 3 views
5

Ich habe versucht, die Ansicht der dehnbaren Sammlung zu erstellen, die Evernote in iOS 7 verwendet, und ich bin wirklich nah daran, es funktioniert zu haben. Es ist mir gelungen, ein benutzerdefiniertes Layout für den Sammlungsansichtsfluss zu erstellen, das die Transformation des Layoutattributs ändert, wenn der Wert für den Inhaltsversatz y außerhalb der Grenzen der Sammlungsansicht liegt. Ich ändere die Layoutattribute in der layoutAttributesForElementsInRect-Methode und verhält sich wie erwartet, außer dass die unteren Zellen verschwinden können, wenn Sie am unteren Rand der Bildlaufansicht klicken. Je weiter Sie den Inhalt verschieben, desto mehr Zellen können verschwinden. Ich denke, die Zellen werden grundsätzlich abgeschnitten. Es passiert nicht an der Spitze und ich würde erwarten, das gleiche Verhalten an beiden Orten zu sehen. So sieht meine Flow-Layout-Implementierung jetzt aus.Erstellen einer dehnbaren UICollectionView wie Evernote auf iOS 7

@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 

Ich zippte auch das Projekt für Leute zum Ausprobieren. Jede Hilfe würde sehr geschätzt werden, da ich ziemlich neu beim Erstellen von benutzerdefinierten Auflistungsansichtslayouts bin. Hier ist der Link zu ihm:

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

Danke an alle!

+0

Ihr Code funktioniert wie erwartet im Simulator. Keine abgeschnittenen Zellen. – Mundi

+0

Ich habe gerade getestet und es scheint gut zu funktionieren in der iPhone Retina (3,5 Zoll) -Simulator, aber das Problem tritt mit dem iPhone Retina (4 Zoll) -Simulator. – cnoon

Antwort

2

Ich konnte das Problem lösen. Ich bin mir nicht sicher, ob es tatsächlich einen Fehler in iOS gibt oder nicht, aber das Problem war, dass die Zellen tatsächlich außerhalb der Inhaltsansicht der Sammlungsansicht übersetzt wurden. Sobald die Zelle weit genug übersetzt wurde, würde sie abgeschnitten werden. Ich finde es interessant, dass dies nicht im Simulator für Nicht-Retina-Displays passiert, aber mit Retina-Displays, weshalb ich das Gefühl habe, dass dies tatsächlich ein Fehler sein könnte.

In diesem Sinne besteht eine Problemumgehung für den Augenblick darin, am oberen und unteren Rand der Sammlungsansicht eine Auffüllung hinzuzufügen, indem die Methode CollectionViewContentSize überschrieben wird. Sobald Sie dies getan haben, müssen Sie die Layout-Attribute für die Zellen ebenfalls anpassen, damit sie an der richtigen Position sind, wenn Sie oben einen Abstand hinzufügen. Der letzte Schritt besteht darin, contentInset für die Sammlungsansicht selbst festzulegen, um sie für das Padding anzupassen. Lassen Sie die Scroll-Indikator-Einfügungen in Ruhe, da diese in Ordnung sind. Hier ist die Implementierung meines finalen Collection-View-Controllers und des benutzerdefinierten Flow-Layouts.

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 

Ich gehe tatsächlich durch diese auf Github und ich werde einen Link zu dem Projekt veröffentlichen, sobald es fertig ist. Danke nochmal allen!

+0

Hier ist das Github-Projekt [link] (https://github.com/cnoon/Stretchy-Collection-View) – cnoon

+0

Großartig :) Weißt du, wie sie diesen coolen Effekt auf die Zelle> machen, wenn Sie einige von ihnen berühren, die Zelle dehnt sich aus und die anderen "entkommen"? – Macistador

Verwandte Themen