Permalink
Browse files

Added delegate method to inform when animated updates finished

  • Loading branch information...
1 parent 87f8f48 commit 150b3722803a00304a1a077f9602d0b2a9dca8ef @myell0w myell0w committed May 5, 2011
Showing with 336 additions and 329 deletions.
  1. +26 −22 Classes/AQGridView.h
  2. +310 −307 Classes/AQGridView.m
View
48 Classes/AQGridView.h
@@ -1,25 +1,25 @@
/*
* AQGridView.h
* AQGridView
- *
+ *
* Created by Jim Dovey on 10/2/2010.
* Copyright 2010 Kobo Inc. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
- *
+ *
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
- *
+ *
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of the project's author nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
@@ -80,6 +80,9 @@ typedef enum {
- (void) gridView: (AQGridView *) gridView didSelectItemAtIndex: (NSUInteger) index numFingersTouch:(NSUInteger)numFingers;
- (void) gridView: (AQGridView *) gridView didDeselectItemAtIndex: (NSUInteger) index;
+// Called after animated updates finished
+- (void) gridViewDidEndUpdateAnimation:(AQGridView *) gridView;
+
// NOT YET IMPLEMENTED
- (void) gridView: (AQGridView *) gridView gestureRecognizer: (UIGestureRecognizer *) recognizer activatedForItemAtIndex: (NSUInteger) index;
@@ -95,38 +98,38 @@ extern NSString * const AQGridViewSelectionDidChangeNotification;
@interface AQGridView : UIScrollView
{
id<AQGridViewDataSource> _dataSource;
-
+
AQGridViewData * _gridData;
NSMutableArray * _updateInfoStack;
NSInteger _animationCount;
-
+
CGRect _visibleBounds;
NSRange _visibleIndices;
NSMutableArray * _visibleCells;
NSMutableDictionary * _reusableGridCells;
-
+
NSSet * _animatingCells;
NSIndexSet * _animatingIndices;
-
+
NSMutableIndexSet * _highlightedIndices;
UIView * _touchedContentView; // weak reference
-
+
UIView * _backgroundView;
UIColor * _separatorColor;
-
+
NSInteger _reloadingSuspendedCount;
NSInteger _displaySuspendedCount;
-
+
NSInteger _updateCount;
-
+
NSUInteger _selectedIndex;
NSUInteger _pendingSelectionIndex;
-
+
CGPoint _touchBeganPosition;
-
+
UIView * _headerView;
UIView * _footerView;
-
+
struct
{
unsigned resizesCellWidths:1;
@@ -145,7 +148,7 @@ extern NSString * const AQGridViewSelectionDidChangeNotification;
unsigned isAnimatingUpdates:1; // unused, see _animationCount instead
unsigned requiresSelection:1;
unsigned contentSizeFillsBounds:1;
-
+
unsigned delegateWillDisplayCell:1;
unsigned delegateWillSelectItem:1;
unsigned delegateWillSelectItemMultiTouch:1;
@@ -155,11 +158,12 @@ extern NSString * const AQGridViewSelectionDidChangeNotification;
unsigned delegateDidDeselectItem:1;
unsigned delegateGestureRecognizerActivated:1;
unsigned delegateAdjustGridCellFrame:1;
-
+ unsigned delegateDidEndUpdateAnimation:1;
+
unsigned dataSourceGridCellSize:1;
-
+
unsigned int isEditing:1;
-
+
unsigned __RESERVED__:1;
} _flags;
}
@@ -265,4 +269,4 @@ extern NSString * const AQGridViewSelectionDidChangeNotification;
// The width/height values returned by this function will be rounded UP to the nearest denominator of the screen width.
- (CGSize) portraitGridCellSizeForGridView: (AQGridView *) gridView;
-@end
+@end
View
617 Classes/AQGridView.m
@@ -1,25 +1,25 @@
/*
* AQGridView.m
* AQGridView
- *
+ *
* Created by Jim Dovey on 10/2/2010.
* Copyright 2010 Kobo Inc. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
- *
+ *
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
- *
+ *
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of the project's author nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
@@ -99,7 +99,7 @@ - (void) _sharedGridViewInit
{
_gridData = [[AQGridViewData alloc] initWithGridView: self];
[_gridData setDesiredCellSize: CGSizeMake(96.0, 128.0)];
-
+
_visibleBounds = self.bounds;
_visibleCells = [[NSMutableArray alloc] init];
_reusableGridCells = [[NSMutableDictionary alloc] init];
@@ -109,10 +109,10 @@ - (void) _sharedGridViewInit
self.clipsToBounds = YES;
self.separatorColor = [UIColor colorWithWhite: 0.85 alpha: 1.0];
self.canCancelContentTouches = YES;
-
+
_selectedIndex = NSNotFound;
_pendingSelectionIndex = NSNotFound;
-
+
_flags.resizesCellWidths = 0;
_flags.numColumns = [_gridData numberOfItemsPerRow];
_flags.separatorStyle = AQGridViewCellSeparatorStyleEmptySpace;
@@ -126,9 +126,9 @@ - (id)initWithFrame: (CGRect) frame
self = [super initWithFrame:frame];
if ( self == nil )
return ( nil );
-
+
[self _sharedGridViewInit];
-
+
return ( self );
}
@@ -137,9 +137,9 @@ - (id) initWithCoder: (NSCoder *) aDecoder
self = [super initWithCoder: aDecoder];
if ( self == nil )
return ( nil );
-
+
[self _sharedGridViewInit];
-
+
return ( self );
}
@@ -163,7 +163,7 @@ - (void)dealloc
[_animatingCells release];
[_headerView release];
[_footerView release];
-
+
[super dealloc];
}
@@ -175,7 +175,7 @@ - (void) setDelegate: (id<AQGridViewDelegate>) obj
if ( (obj != nil) && ([obj conformsToProtocol: @protocol(AQGridViewDelegate)] == NO ))
[NSException raise: NSInvalidArgumentException format: @"Argument to -setDelegate must conform to the AQGridViewDelegate protocol"];
[super setDelegate: obj];
-
+
_flags.delegateWillDisplayCell = [obj respondsToSelector: @selector(gridView:willDisplayCell:forItemAtIndex:)];
_flags.delegateWillSelectItem = [obj respondsToSelector: @selector(gridView:willSelectItemAtIndex:)];
_flags.delegateWillSelectItemMultiTouch = [obj respondsToSelector: @selector(gridView:willSelectItemAtIndex:numFingersTouch:)];
@@ -185,6 +185,7 @@ - (void) setDelegate: (id<AQGridViewDelegate>) obj
_flags.delegateDidDeselectItem = [obj respondsToSelector: @selector(gridView:didDeselectItemAtIndex:)];
_flags.delegateGestureRecognizerActivated = [obj respondsToSelector: @selector(gridView:gestureRecognizer:activatedForItemAtIndex:)];
_flags.delegateAdjustGridCellFrame = [obj respondsToSelector: @selector(gridView:adjustCellFrame:withinGridCellFrame:)];
+ _flags.delegateDidEndUpdateAnimation = [obj respondsToSelector:@selector(gridViewDidEndUpdateAnimation:)];
}
- (id<AQGridViewDelegate>) delegate
@@ -199,9 +200,9 @@ - (void) setDataSource: (id<AQGridViewDataSource>) obj
{
if ((obj != nil) && ([obj conformsToProtocol: @protocol(AQGridViewDataSource)] == NO ))
[NSException raise: NSInvalidArgumentException format: @"Argument to -setDataSource must conform to the AQGridViewDataSource protocol"];
-
+
_dataSource = obj;
-
+
_flags.dataSourceGridCellSize = [obj respondsToSelector: @selector(portraitGridCellSizeForGridView:)];
}
@@ -282,7 +283,7 @@ - (void) setResizesCellWidthToFit: (BOOL) value
int i = (value ? 1 : 0);
if ( _flags.resizesCellWidths == i )
return;
-
+
_flags.resizesCellWidths = i;
[self setNeedsLayout];
}
@@ -307,7 +308,7 @@ - (void) setUsesPagedHorizontalScrolling: (BOOL) value
int i = (value ? 1 : 0);
if ( _flags.usesPagedHorizontalScrolling == i )
return;
-
+
_flags.usesPagedHorizontalScrolling = i;
[self setNeedsLayout];
}
@@ -321,14 +322,14 @@ - (void) setSeparatorStyle: (AQGridViewCellSeparatorStyle) style
{
if ( style == _flags.separatorStyle )
return;
-
+
_flags.separatorStyle = style;
-
+
for ( AQGridViewCell * cell in _visibleCells )
{
cell.separatorStyle = style;
}
-
+
[self setNeedsLayout];
}
@@ -366,10 +367,10 @@ - (void) setGridHeaderView: (UIView *) newHeaderView
{
if ( newHeaderView == _headerView )
return;
-
+
[_headerView removeFromSuperview];
[_headerView release];
-
+
_headerView = [newHeaderView retain];
if ( _headerView == nil )
{
@@ -380,7 +381,7 @@ - (void) setGridHeaderView: (UIView *) newHeaderView
[self addSubview: _headerView];
_gridData.topPadding = _headerView.frame.size.height;
}
-
+
[self setNeedsLayout];
}
@@ -393,10 +394,10 @@ - (void) setGridFooterView: (UIView *) newFooterView
{
if ( newFooterView == _footerView )
return;
-
+
[_footerView removeFromSuperview];
[_footerView release];
-
+
_footerView = [newFooterView retain];
if ( _footerView == nil )
{
@@ -407,7 +408,7 @@ - (void) setGridFooterView: (UIView *) newFooterView
[self addSubview: _footerView];
_gridData.bottomPadding = _footerView.frame.size.height;
}
-
+
[self setNeedsLayout];
}
@@ -426,14 +427,14 @@ - (void) setAnimatingCells: (NSSet *) set
[set retain];
[_animatingCells release];
_animatingCells = set;
-
+
NSMutableIndexSet * indices = [[NSMutableIndexSet alloc] init];
for ( AQGridViewAnimatorItem * item in set )
{
if ( item.index != NSNotFound )
[indices addIndex: item.index];
}
-
+
self.animatingIndices = indices;
[indices release];
}
@@ -448,14 +449,14 @@ - (void) updateContentRectWithOldMaxLocation: (CGPoint) oldMaxLocation gridSize:
// The following line prevents an update leading to unneccessary auto-scrolling
// Before this fix, AQGridView animation always caused scrolling to the most bottom line
if (CGSizeEqualToSize(self.contentSize, gridSize)) return;
-
+
// update content size
self.contentSize = gridSize;
-
+
// fix content offset if applicable
CGPoint offset = self.contentOffset;
CGPoint oldOffset = offset;
-
+
if ( offset.y + self.bounds.size.height > gridSize.height )
{
offset.y = MAX(0.0, self.contentSize.height - self.bounds.size.height);
@@ -471,7 +472,7 @@ - (void) updateContentRectWithOldMaxLocation: (CGPoint) oldMaxLocation gridSize:
offset.x = MAX(0.0, self.contentSize.width - self.bounds.size.width);
}
}
-
+
//NSLog( @"Resetting offset from %@ to %@", NSStringFromCGPoint(oldOffset), NSStringFromCGPoint(offset) );
self.contentOffset = offset;
}
@@ -480,14 +481,14 @@ - (void) handleGridViewBoundsChanged: (CGRect) oldBounds toNewBounds: (CGRect) b
{
CGSize oldGridSize = [_gridData sizeForEntireGrid];
BOOL wasAtBottom = ((oldGridSize.height != 0.0) && (CGRectGetMaxY(oldBounds) == oldGridSize.height));
-
+
[_gridData gridViewDidChangeBoundsSize: bounds.size];
_flags.numColumns = [_gridData numberOfItemsPerRow];
CGSize newGridSize = [_gridData sizeForEntireGrid];
-
+
CGPoint oldMaxLocation = CGPointMake(CGRectGetMaxX(oldBounds), CGRectGetMaxY(oldBounds));
[self updateContentRectWithOldMaxLocation: oldMaxLocation gridSize: newGridSize];
-
+
if ( (wasAtBottom) && (!CGPointEqualToPoint(oldBounds.origin, CGPointZero)) && (newGridSize.height > oldGridSize.height) )
{
CGRect contentRect = self.bounds;
@@ -497,7 +498,7 @@ - (void) handleGridViewBoundsChanged: (CGRect) oldBounds toNewBounds: (CGRect) b
self.contentOffset = contentRect.origin;
}
}
-
+
[self updateVisibleGridCellsNow];
_flags.allCellsNeedLayout = 1;
}
@@ -511,7 +512,7 @@ - (void)setContentOffset: (CGPoint) contentOffset animated: (BOOL) animate
{
// Call our super duper method
[super setContentOffset: contentOffset animated: animate];
-
+
// for long grids, ensure there are visible cells when scrolled to
if (!animate)
{
@@ -528,7 +529,7 @@ - (void) setContentSize: (CGSize) newSize
{
if ( (_flags.contentSizeFillsBounds == 1) && (newSize.height < self.bounds.size.height) )
newSize.height = self.bounds.size.height;
-
+
if (self.gridFooterView)
{
// In-call status bar influences footer position
@@ -540,15 +541,15 @@ - (void) setContentSize: (CGSize) newSize
if (newSize.height < footerHeight + minimumHeight)
newSize.height = minimumHeight;
}
-
+
newSize.height = fmax(newSize.height, self.frame.size.height+1);
-
+
CGSize oldSize = self.contentSize;
[super setContentSize: newSize];
-
+
if ( oldSize.width != newSize.width )
[_gridData gridViewDidChangeBoundsSize: newSize];
-
+
if ( CGRectGetMaxY(self.bounds) > newSize.height )
{
CGRect b = self.bounds;
@@ -563,7 +564,7 @@ - (void) setFrame: (CGRect) newFrame
CGRect oldBounds = self.bounds;
[super setFrame: newFrame];
CGRect newBounds = self.bounds;
-
+
if ( newBounds.size.width != oldBounds.size.width )
[self handleGridViewBoundsChanged: oldBounds toNewBounds: newBounds];
}
@@ -573,7 +574,7 @@ - (void) setBounds: (CGRect) bounds
CGRect oldBounds = self.bounds;
[super setBounds: bounds];
bounds = self.bounds; // in case it was modified
-
+
if ( !CGSizeEqualToSize(bounds.size, oldBounds.size) )
[self handleGridViewBoundsChanged: oldBounds toNewBounds: bounds];
}
@@ -597,9 +598,9 @@ - (AQGridViewCell *) dequeueReusableCellWithIdentifier: (NSString *) reuseIdenti
AQGridViewCell * cell = [[cells anyObject] retain];
if ( cell == nil )
return ( nil );
-
+
[cell prepareForReuse];
-
+
[cells removeObject: cell];
return ( [cell autorelease] );
}
@@ -619,8 +620,8 @@ - (void) enqueueReusableCells: (NSArray *) reusableCells
{
NSLog( @"Warning: tried to add duplicate gridview cell" );
continue;
- }
-
+ }
+
[reuseSet addObject: cell];
}
}
@@ -637,30 +638,30 @@ - (void) reloadData
{
if ( _reloadingSuspendedCount != 0 )
return;
-
+
if ( _flags.dataSourceGridCellSize == 1 )
{
[_gridData setDesiredCellSize: [_dataSource portraitGridCellSizeForGridView: self]];
_flags.numColumns = [_gridData numberOfItemsPerRow];
}
-
+
_gridData.numberOfItems = [_dataSource numberOfItemsInGridView: self];
-
+
// update our content size as appropriate
self.contentSize = [_gridData sizeForEntireGrid];
-
+
// fix up the visible index list
NSUInteger cutoff = MAX(0, _gridData.numberOfItems-_visibleIndices.length);
_visibleIndices.location = MIN(_visibleIndices.location, cutoff);
_visibleIndices.length = 0;
-
+
// remove all existing cells
[_visibleCells makeObjectsPerformSelector: @selector(removeFromSuperview)];
[self enqueueReusableCells: _visibleCells];
[_visibleCells removeAllObjects];
-
+
// -layoutSubviews will update the visible cell list
-
+
// layout -- no animation
[self setNeedsLayout];
_flags.allCellsNeedLayout = 1;
@@ -672,65 +673,65 @@ - (void) layoutSubviews
{
if ( (_flags.needsReload == 1) && (_animationCount == 0) && (_reloadingSuspendedCount == 0) )
[self reloadData];
-
+
if ( (_reloadingSuspendedCount == 0) && (!CGRectIsEmpty([self gridViewVisibleBounds])) )
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[self updateVisibleGridCellsNow];
[pool release];
}
-
+
if ( _flags.allCellsNeedLayout == 1 )
{
_flags.allCellsNeedLayout = 0;
if ( _visibleIndices.length != 0 )
[self layoutAllCells];
}
-
+
CGRect rect = CGRectZero;
rect.size.width = self.bounds.size.width;
rect.size.height = self.contentSize.height - (_gridData.topPadding + _gridData.bottomPadding);
rect.origin.y += _gridData.topPadding;
-
+
// Make sure background is an integral number of rows tall. That way, it draws patterned colours correctly on all OSes.
CGRect backgroundRect = rect;
-
+
if ([self backgroundViewExtendsUp]) {
backgroundRect.origin.y = backgroundRect.origin.y - MAX_BOUNCE_DISTANCE;
backgroundRect.size.height += MAX_BOUNCE_DISTANCE; // don't just move it, grow it
}
-
+
if ([self backgroundViewExtendsDown]) {
backgroundRect.size.height = backgroundRect.size.height + MAX_BOUNCE_DISTANCE;
}
-
- CGFloat minimumHeight = rect.size.height,
+
+ CGFloat minimumHeight = rect.size.height,
actualHeight = 0;
-
+
if (([_gridData numberOfItems] == 0) || ([_gridData numberOfItemsPerRow] == 0)) {
-
+
actualHeight = [_gridData cellSize].height;
-
+
} else {
-
+
actualHeight = [_gridData cellSize].height * ([_gridData numberOfItems] / [_gridData numberOfItemsPerRow] + 1);
-
+
}
for (; actualHeight < minimumHeight; actualHeight += [_gridData cellSize].height) {
}
backgroundRect.size.height = actualHeight;
-
+
self.backgroundView.frame = backgroundRect;
-
+
if ( _headerView != nil )
{
rect = _headerView.frame;
rect.origin = CGPointZero;
rect.size.width = self.bounds.size.width;
_headerView.frame = rect;
}
-
+
if ( _footerView != nil )
{
rect = _footerView.frame;
@@ -747,7 +748,7 @@ - (CGRect) rectForItemAtIndex: (NSUInteger) index
// simple case -- there's a cell already, we can just ask for its frame
if ( NSLocationInRange(index, _visibleIndices) )
return ( [[_visibleCells objectAtIndex: [self visibleCellListIndexForItemIndex: index]] frame] );
-
+
// complex case-- compute the frame manually
return ( [self fixCellFrame: CGRectZero forGridRect: [_gridData cellRectAtIndex: index]] );
}
@@ -756,7 +757,7 @@ - (AQGridViewCell *) cellForItemAtIndex: (NSUInteger) index
{
//if ( NSLocationInRange(index, _visibleIndices) == NO )
// return ( nil );
-
+
// we don't clip to visible range-- when animating edits the visible cell list can contain extra items
NSUInteger visibleCellListIndex = [self visibleCellListIndexForItemIndex: index];
if ( visibleCellListIndex < [_visibleCells count] )
@@ -774,7 +775,7 @@ - (NSUInteger) indexForCell: (AQGridViewCell *) cell
NSUInteger index = [_visibleCells indexOfObject:cell];
if (index == NSNotFound)
return NSNotFound;
-
+
return _visibleIndices.location + index;
}
@@ -798,27 +799,27 @@ - (void) scrollToItemAtIndex: (NSUInteger) index atScrollPosition: (AQGridViewSc
{
CGRect gridRect = [_gridData cellRectAtIndex: index];
CGRect targetRect = self.bounds;
-
+
switch ( scrollPosition )
{
case AQGridViewScrollPositionNone:
default:
targetRect = gridRect; // no special coordinate handling
break;
-
+
case AQGridViewScrollPositionTop:
targetRect.origin.y = gridRect.origin.y; // set target y origin to cell's y origin
break;
-
+
case AQGridViewScrollPositionMiddle:
targetRect.origin.y = MAX(gridRect.origin.y - (CGFloat)ceilf((targetRect.size.height - gridRect.size.height) * 0.5), 0.0);
break;
-
+
case AQGridViewScrollPositionBottom:
targetRect.origin.y = MAX((CGFloat)floorf(gridRect.origin.y - (targetRect.size.height - gridRect.size.height)), 0.0);
break;
}
-
+
[self scrollRectToVisible: targetRect animated: animated];
// for long grids, ensure there are visible cells when scrolled to
@@ -847,34 +848,34 @@ - (void) fixCellsFromAnimation
if ( cell.hiddenForAnimation )
{
cell.hiddenForAnimation = NO;
-
+
if ( _flags.delegateWillDisplayCell == 1 )
[self delegateWillDisplayCell: cell atIndex: cell.displayIndex];
-
+
cell.hidden = NO;
}
}
-
+
// update the visible item list appropriately
NSIndexSet * indices = [_gridData indicesOfCellsInRect: self.bounds];
if ( [indices count] == 0 )
{
_visibleIndices.location = 0;
_visibleIndices.length = 0;
-
+
[_visibleCells makeObjectsPerformSelector: @selector(removeFromSuperview)];
[self enqueueReusableCells: _visibleCells];
[_visibleCells removeAllObjects];
-
+
// update the content size/offset based on the new grid data
CGPoint oldMaxLocation = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds));
[self updateContentRectWithOldMaxLocation: oldMaxLocation gridSize: [_gridData sizeForEntireGrid]];
return;
}
-
+
_visibleIndices.location = [indices firstIndex];
_visibleIndices.length = [indices count];
-
+
NSMutableArray * newVisibleCells = [[NSMutableArray alloc] initWithCapacity: _visibleIndices.length];
for ( AQGridViewAnimatorItem * item in self.animatingCells )
{
@@ -883,38 +884,38 @@ - (void) fixCellsFromAnimation
[item.animatingView removeFromSuperview];
continue;
}
-
+
if ( [self isRectVisible: [_gridData cellRectForPoint: item.animatingView.center]] == NO )
{
[item.animatingView removeFromSuperview];
continue;
}
-
+
[newVisibleCells addObject: item.animatingView];
}
-
+
//NSAssert([newVisibleCells count] == _visibleIndices.length, @"visible cell count after animation doesn't match visible indices");
-
+
[newVisibleCells sortUsingSelector: @selector(compareOriginAgainstCell:)];
[_visibleCells removeObjectsInArray: newVisibleCells];
[_visibleCells makeObjectsPerformSelector: @selector(removeFromSuperview)];
[_visibleCells setArray: newVisibleCells];
[newVisibleCells release];
self.animatingCells = nil;
-
+
NSMutableSet * removals = [[NSMutableSet alloc] init];
for ( UIView * view in self.subviews )
{
if ( [view isKindOfClass: [AQGridViewCell class]] == NO )
continue;
-
+
if ( [_visibleCells containsObject: view] == NO )
[removals addObject: view];
}
-
+
[removals makeObjectsPerformSelector: @selector(removeFromSuperview)];
[removals release];
-
+
// update the content size/offset based on the new grid data
CGPoint oldMaxLocation = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds));
[self updateContentRectWithOldMaxLocation: oldMaxLocation gridSize: [_gridData sizeForEntireGrid]];
@@ -923,7 +924,7 @@ - (void) fixCellsFromAnimation
- (void) setupUpdateAnimations
{
_reloadingSuspendedCount++;
-
+
AQGridViewUpdateInfo * info = [[AQGridViewUpdateInfo alloc] initWithOldGridData: _gridData forGridView: self];
[_updateInfoStack addObject: info];
[info release];
@@ -932,52 +933,52 @@ - (void) setupUpdateAnimations
- (void) endUpdateAnimations
{
NSAssert([_updateInfoStack lastObject] != nil, @"_updateInfoStack should not be empty at this point" );
-
+
AQGridViewUpdateInfo * info = [_updateInfoStack lastObject];
-
+
if ( info.numberOfUpdates == 0 )
{
[_updateInfoStack removeObject: info];
_reloadingSuspendedCount--;
return;
}
-
+
NSUInteger expectedItemCount = [info numberOfItemsAfterUpdates];
NSUInteger actualItemCount = [_dataSource numberOfItemsInGridView: self];
if ( expectedItemCount != actualItemCount )
{
NSUInteger numAdded = [[info sortedInsertItems] count];
NSUInteger numDeleted = [[info sortedDeleteItems] count];
-
+
[_updateInfoStack removeObject: info];
_reloadingSuspendedCount--;
-
+
[NSException raise: NSInternalInconsistencyException format: @"Invalid number of items in AQGridView: Started with %u, added %u, deleted %u. Expected %u items after changes, but got %u", (unsigned)_gridData.numberOfItems, (unsigned)numAdded, (unsigned)numDeleted, (unsigned)expectedItemCount, (unsigned)actualItemCount];
}
-
+
// there's a race condition with the info's removal from the stack if there are no animations taking place,
// where -cellUpdateAnimationStopped:finished:context: is called immediately, before we've finished with the
// object. Therefore we retain it while we want to use it, just in case
[info retain];
-
+
[info cleanupUpdateItems];
_animationCount++;
//NSAssert(_animationCount == 1, @"Stacked animations occurring!!");
-
+
[UIView beginAnimations: @"CellUpdates" context: info];
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector: @selector(cellUpdateAnimationStopped:finished:context:)];
[UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration: 0.3];
-
+
self.animatingCells = [info animateCellUpdatesUsingVisibleContentRect: [self gridViewVisibleBounds]];
-
-
+
+
[_gridData release];
_gridData = [[info newGridViewData] retain];
if ( _selectedIndex != NSNotFound )
_selectedIndex = [info newIndexForOldIndex: _selectedIndex];
-
+
[info release];
_reloadingSuspendedCount--;
[UIView commitAnimations];
@@ -986,16 +987,18 @@ - (void) endUpdateAnimations
- (void) cellUpdateAnimationStopped: (NSString *) animationID finished: (BOOL) finished context: (void *) context
{
AQGridViewUpdateInfo * info = (AQGridViewUpdateInfo *)context;
-
+
// if nothing was animated, we don't have to do anything at all
// if ( self.animatingCells.count != 0 )
[self fixCellsFromAnimation];
-
+
// NB: info becomes invalid at this point
[_updateInfoStack removeObject: info];
_animationCount--;
-
+
//_reloadingSuspendedCount--;
+ if ( _flags.delegateDidEndUpdateAnimation == 1 )
+ [self.delegate gridViewDidEndUpdateAnimation: self];
}
- (void) beginUpdates
@@ -1013,13 +1016,13 @@ - (void) endUpdates
- (void) _updateItemsAtIndices: (NSIndexSet *) indices updateAction: (AQGridViewUpdateAction) action withAnimation: (AQGridViewItemAnimation) animation
{
BOOL needsAnimationSetup = ([_updateInfoStack count] <= _animationCount);
-
+
// not in the middle of an update loop -- start animations here
if ( needsAnimationSetup )
[self setupUpdateAnimations];
-
+
[[_updateInfoStack lastObject] updateItemsAtIndices: indices updateAction: action withAnimation: animation];
-
+
// not in the middle of an update loop -- commit animations here
if ( needsAnimationSetup )
[self endUpdateAnimations];
@@ -1043,20 +1046,20 @@ - (void) reloadItemsAtIndices: (NSIndexSet *) indices withAnimation: (AQGridView
- (void) moveItemAtIndex: (NSUInteger) index toIndex: (NSUInteger) newIndex withAnimation: (AQGridViewItemAnimation) animation
{
BOOL needsAnimationSetup = ([_updateInfoStack count] <= _animationCount);
-
+
if ( needsAnimationSetup )
[self setupUpdateAnimations];
-
+
[[_updateInfoStack lastObject] moveItemAtIndex: index toIndex: newIndex withAnimation: animation];
-
+
if ( needsAnimationSetup )
[self endUpdateAnimations];
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
_flags.isEditing = (editing ? 1 : 0);
-
+
NSArray *visibleCells = [self visibleCells];
for (AQGridViewCell *aCell in visibleCells) {
[aCell setEditing:editing animated:animated];
@@ -1079,7 +1082,7 @@ - (void) highlightItemAtIndex: (NSUInteger) index animated: (BOOL) animated scro
[self scrollToItemAtIndex: index atScrollPosition: position animated: animated];
return;
}
-
+
if ( index == NSNotFound )
{
NSUInteger i = [_highlightedIndices firstIndex];
@@ -1089,15 +1092,15 @@ - (void) highlightItemAtIndex: (NSUInteger) index animated: (BOOL) animated scro
[cell setHighlighted: NO animated: animated];
i = [_highlightedIndices indexGreaterThanIndex: i];
}
-
+
[_highlightedIndices removeAllIndexes];
return;
}
-
+
AQGridViewCell * cell = [self cellForItemAtIndex: index];
[cell setHighlighted: YES animated: animated];
[_highlightedIndices addIndex: index];
-
+
if ( position != AQGridViewScrollPositionNone )
[self scrollToItemAtIndex: index atScrollPosition: position animated: animated];
}
@@ -1106,13 +1109,13 @@ - (void) unhighlightItemAtIndex: (NSUInteger) index animated: (BOOL) animated
{
if ( [_highlightedIndices containsIndex: index] == NO )
return;
-
+
[_highlightedIndices removeIndex: index];
-
+
// don't remove highlighting if the cell is actually the selected cell
if ( index == _selectedIndex )
return;
-
+
AQGridViewCell * cell = [self cellForItemAtIndex: index];
if ( cell != nil )
[cell setHighlighted: NO animated: animated];
@@ -1122,16 +1125,16 @@ - (void) _deselectItemAtIndex: (NSUInteger) index animated: (BOOL) animated noti
{
if ( _selectedIndex != index )
return;
-
+
if ( notifyDelegate && _flags.delegateWillDeselectItem )
[self.delegate gridView: self willDeselectItemAtIndex: index];
-
+
_selectedIndex = NSNotFound;
[[self cellForItemAtIndex: index] setSelected: NO animated: animated];
-
+
if ( notifyDelegate && _flags.delegateDidDeselectItem )
[self.delegate gridView: self didDeselectItemAtIndex: index];
-
+
if ( notifyDelegate )
{
[[NSNotificationCenter defaultCenter] postNotificationName: AQGridViewSelectionDidChangeNotification
@@ -1145,38 +1148,38 @@ - (void) _selectItemAtIndex: (NSUInteger) index animated: (BOOL) animated
{
if ( _selectedIndex == index )
return; // already selected this item
-
+
if ( _selectedIndex != NSNotFound )
[self _deselectItemAtIndex: _selectedIndex animated: animated notifyDelegate: notifyDelegate];
-
+
if ( _flags.allowsSelection == 0 )
return;
-
+
if ( notifyDelegate && _flags.delegateWillSelectItem )
index = [self.delegate gridView: self willSelectItemAtIndex: index];
-
+
if ( notifyDelegate && _flags.delegateWillSelectItemMultiTouch )
index = [self.delegate gridView: self willSelectItemAtIndex: index
numFingersTouch:numFingers];
-
+
_selectedIndex = index;
[[self cellForItemAtIndex: index] setSelected: YES animated: animated];
-
+
if ( position != AQGridViewScrollPositionNone )
[self scrollToItemAtIndex: index atScrollPosition: position animated: animated];
-
+
if ( notifyDelegate )
{
[[NSNotificationCenter defaultCenter] postNotificationName: AQGridViewSelectionDidChangeNotification
object: self];
}
-
+
if ( notifyDelegate && _flags.delegateDidSelectItem )
[self.delegate gridView: self didSelectItemAtIndex: index];
-
+
if ( notifyDelegate && _flags.delegateDidSelectItemMultiTouch )
[self.delegate gridView: self didSelectItemAtIndex: index numFingersTouch:numFingers];
-
+
// ensure that the selected item is no longer marked as just 'highlighted' (that's an intermediary state)
[_highlightedIndices removeIndex: index];
}
@@ -1205,30 +1208,30 @@ - (void) setBackgroundView: (UIView *) newView
{
if ( newView == _backgroundView )
return;
-
+
[_backgroundView removeFromSuperview];
[_backgroundView release];
-
+
_backgroundView = [newView retain];
_backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
CGRect frame = self.bounds;
frame.size = self.contentSize;
-
+
CGRect backgroundRect = CGRectMake(0.0f, 0.0f, self.bounds.size.width, self.bounds.size.height);
-
+
if ([self backgroundViewExtendsUp]) {
backgroundRect.origin.y = backgroundRect.origin.y - MAX_BOUNCE_DISTANCE;
backgroundRect.size.height += MAX_BOUNCE_DISTANCE; // don't just move it, grow it
}
-
+
if ([self backgroundViewExtendsDown]) {
backgroundRect.size.height = backgroundRect.size.height + MAX_BOUNCE_DISTANCE;
}
-
+
_backgroundView.frame = backgroundRect;
-
+
[self insertSubview: _backgroundView atIndex: 0];
-
+
// this view is already laid out nicely-- no need to call -setNeedsLayout at all
}
@@ -1241,11 +1244,11 @@ - (void) setSeparatorColor: (UIColor *) color
{
if ( color == _separatorColor )
return;
-
+
[color retain];
[_separatorColor release];
_separatorColor = color;
-
+
for ( AQGridViewCell * cell in _visibleCells )
{
cell.separatorColor = _separatorColor;
@@ -1276,23 +1279,23 @@ - (BOOL) _canSelectItemContainingHitView: (UIView *) hitView
// Simply querying the superview will not work if the hit view is a subview of the contentView, e.g. its superview is a plain UIView *inside* a cell
-
+
if ( [[hitView superview] isKindOfClass: [AQGridViewCell class]] )
return ( YES );
-
+
if ( [hitView isKindOfClass: [AQGridViewCell class]] )
return ( YES );
-
+
CGPoint hitCenter = [self convertPoint:[hitView center] fromView:hitView];
-
+
for ( AQGridViewCell *aCell in [[[self visibleCells] copy] autorelease])
{
-
+
if ( CGRectContainsPoint( aCell.frame, hitCenter ) )
return ( YES );
-
+
}
-
+
return ( NO );
}
@@ -1327,18 +1330,18 @@ - (BOOL) _gestureRecognizerIsHandlingTouches: (NSSet *) touches
case UIGestureRecognizerStateCancelled:
case UIGestureRecognizerStateFailed:
continue;
-
+
default:
break;
}
-
+
if ( [recognizer numberOfTouches] == [touches count] )
{
// simple version:
// pick a touch from our event's set, and see if it's in the recognizer's set
UITouch * touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView: self];
-
+
for ( NSUInteger i = 0; i < [recognizer numberOfTouches]; i++ )
{
CGPoint test = [recognizer locationOfTouch: i inView: self];
@@ -1349,26 +1352,26 @@ - (BOOL) _gestureRecognizerIsHandlingTouches: (NSSet *) touches
}
}
}
-
+
return ( NO );
}
- (void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event
{
_flags.ignoreTouchSelect = ([self isDragging] ? 1 : 0);
-
+
UITouch * touch = [touches anyObject];
_touchBeganPosition = [touch locationInView: nil];
if ( (touch != nil) && (_pendingSelectionIndex == NSNotFound) )
{
CGPoint pt = [touch locationInView: self];
UIView * hitView = [self _basicHitTest: pt withEvent: event];
_touchedContentView = [hitView retain];
-
+
// unhighlight anything not here
if ( hitView != self )
[self highlightItemAtIndex: NSNotFound animated: NO scrollPosition: AQGridViewScrollPositionNone];
-
+
if ( [self _canSelectItemContainingHitView: hitView] )
{
NSUInteger index = [self indexForItemAtPoint: pt];
@@ -1377,7 +1380,7 @@ - (void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event
if ( _flags.allowsSelection == 1 )
{
_pendingSelectionIndex = index;
-
+
// NB: In UITableView:
// if ( [self usesGestureRecognizers] && [self isDragging] ) skip next line
[self performSelector: @selector(_gridViewDeferredTouchesBegan:)
@@ -1387,14 +1390,14 @@ - (void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event
}
}
}
-
+
[super touchesBegan: touches withEvent: event];
}
/*
- (void) _cancelContentTouchUsingEvent: (UIEvent *) event forced: (BOOL) forced
{
static char * name = "_cancelContentTouchWithEvent:forced:";
-
+
// more manual ObjC runtime calls...
SEL selector = sel_getUid( name );
objc_msgSend( self, selector, event, forced );
@@ -1410,14 +1413,14 @@ - (void) touchesMoved: (NSSet *) touches withEvent: (UIEvent *) event
if ( [self _gestureRecognizerIsHandlingTouches: touches] )
goto passToSuper; // I feel all icky now
}
-
+
//[self _cancelContentTouchUsingEvent: event forced: NO];
[self highlightItemAtIndex: NSNotFound animated: NO scrollPosition: AQGridViewScrollPositionNone];
_flags.ignoreTouchSelect = 1;
[_touchedContentView release];
_touchedContentView = nil;
}
-
+
passToSuper:
[super touchesMoved: touches withEvent: event];
}
@@ -1427,57 +1430,57 @@ - (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event
[[self class] cancelPreviousPerformRequestsWithTarget: self
selector: @selector(_gridViewDeferredTouchesBegan:)
object: nil];
-
+
UIView * hitView = [_touchedContentView retain];
_touchedContentView = nil;
-
+
[super touchesEnded: touches withEvent: event];
if ( _touchedContentView != nil )
{
[hitView release];
hitView = [_touchedContentView retain];
}
-
+
if ( [hitView superview] == nil )
{
[hitView release];
hitView = nil;
}
-
+
// poor-man's goto
do
{
if ( self.dragging )
break;
-
+
UITouch * touch = [touches anyObject];
if ( touch == nil )
break;
-
+
CGPoint pt = [touch locationInView: self];
if ( (hitView != nil) && ([self _canSelectItemContainingHitView: hitView] == NO) )
break;
-
+
if ( _pendingSelectionIndex != [self indexForItemAtPoint: pt] )
break;
-
+
if ( _flags.allowsSelection == 0 )
break;
-
+
NSSet *touchEventSet = [event allTouches];
-
+
// run this on the next runloop tick
UserSelectItemIndexParams* selectorParams = [[[UserSelectItemIndexParams alloc] init] autorelease];
selectorParams.indexNum = _pendingSelectionIndex;
selectorParams.numFingers = [touchEventSet count];
[self performSelector: @selector(_userSelectItemAtIndex:)
withObject: selectorParams
afterDelay:0.0];
-
+
[hitView release];
-
+
} while (0);
-
+
if ( _pendingSelectionIndex != NSNotFound )
[self unhighlightItemAtIndex: _pendingSelectionIndex animated: NO];
_pendingSelectionIndex = NSNotFound;
@@ -1531,7 +1534,7 @@ - (void) sortVisibleCellList
if ( OSAtomicCompareAndSwapPtrBarrier(nil, obj, (void * volatile *)&__sortDescriptors) == false )
[obj release]; // already stored by another thread
}
-
+
[_visibleCells sortUsingDescriptors: __sortDescriptors];
}
@@ -1545,16 +1548,16 @@ - (void) updateVisibleGridCellsNow
{
if ( _reloadingSuspendedCount > 0 )
return;
-
+
_reloadingSuspendedCount++;
-
-
+
+
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSIndexSet * newVisibleIndices = [_gridData indicesOfCellsInRect: [self gridViewVisibleBounds]];
-
+
BOOL enableAnim = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled: NO];
-
+
@try
{
// a couple of simple tests
@@ -1564,10 +1567,10 @@ - (void) updateVisibleGridCellsNow
{
// something has changed. Compute intersections and remove/add cells as required
NSIndexSet * currentVisibleIndices = [NSIndexSet indexSetWithIndexesInRange: _visibleIndices];
-
+
// index sets for removed and inserted items
NSMutableIndexSet * removedIndices = nil, * insertedIndices = nil;
-
+
// handle the simple case first
// TODO: if we replace _visibleIndices with an index set, this comparison will have to change
if ( [currentVisibleIndices intersectsIndexesInRange: _visibleIndices] == NO )
@@ -1580,71 +1583,71 @@ - (void) updateVisibleGridCellsNow
removedIndices = [[[currentVisibleIndices aq_indexesOutsideIndexSet: newVisibleIndices] mutableCopy] autorelease];
insertedIndices = [[[newVisibleIndices aq_indexesOutsideIndexSet: currentVisibleIndices] mutableCopy] autorelease];
}
-
+
if ( [removedIndices count] != 0 )
{
NSMutableIndexSet * shifted = [removedIndices mutableCopy];
-
+
// get an index set for everything being removed relative to items' locations within the visible cell list
[shifted shiftIndexesStartingAtIndex: [removedIndices firstIndex] by: 0 - (NSInteger)_visibleIndices.location];
//NSLog( @"Removed indices relative to visible cell list: %@", shifted );
-
+
NSUInteger index=[shifted firstIndex];
while(index != NSNotFound){
NSLog(@"%i >= %i ?", index, [_visibleCells count]);
if (index >= [_visibleCells count]) {
[shifted removeIndex:index];
- }
+ }
index=[shifted indexGreaterThanIndex: index];
}
-
+
// pull out the cells for manipulation
NSMutableArray * removedCells = [[_visibleCells objectsAtIndexes: shifted] mutableCopy];
-
+
// remove them from the visible list
[_visibleCells removeObjectsInArray: removedCells];
//NSLog( @"After removals, visible cells count = %lu", (unsigned long)[_visibleCells count] );
-
+
// don't need this any more
[shifted release]; shifted = nil;
-
+
// remove cells from the view hierarchy -- but only if they're not being animated by something else
NSArray * animating = [[self.animatingCells valueForKey: @"animatingView"] allObjects];
if ( animating != nil )
[removedCells removeObjectsInArray: animating];
-
+
// these are not being displayed or animated offscreen-- take them off the screen immediately
[removedCells makeObjectsPerformSelector: @selector(removeFromSuperview)];
-
+
// put them into the cell reuse queue
[self enqueueReusableCells: removedCells];
-
+
[removedCells release];
}
-
+
if ( [insertedIndices count] != 0 )
{
// some items are going in -- put them at the end and the sort function will move them to the right index during layout
// if any of these new indices correspond to animating cells (NOT UIImageViews) then copy them into the visible cell list
NSMutableIndexSet * animatingInserted = [insertedIndices mutableCopy];
-
+
// compute the intersection of insertedIndices and _animatingIndices
NSUInteger idx = [insertedIndices firstIndex];
while ( idx != NSNotFound )
{
if ( [_animatingIndices containsIndex: idx] == NO )
[animatingInserted removeIndex: idx];
-
+
idx = [insertedIndices indexGreaterThanIndex: idx];
}
-
+
if ( [animatingInserted count] != 0 )
{
for ( AQGridViewAnimatorItem * item in _animatingCells )
{
if ( [newVisibleIndices containsIndex: item.index] == NO )
continue;
-
+
if ( [item.animatingView isKindOfClass: [AQGridViewCell class]] )
{
// ensure this is in the visible cell list
@@ -1659,33 +1662,33 @@ - (void) updateVisibleGridCellsNow
AQGridViewCell * cell = [self createPreparedCellForIndex: idx];
//[_visibleCells addObject: cell];
[self doAddVisibleCell: cell];
-
+
// we don't tell the delegate yet, we just hide it
cell.hiddenForAnimation = YES;
}
}
-
+
// remove these from the set of indices for which we will generate new cells
[insertedIndices removeIndexes: animatingInserted];
}
-
+
[animatingInserted release];
-
+
// insert cells for these indices
idx = [insertedIndices firstIndex];
while ( idx != NSNotFound )
{
AQGridViewCell * cell = [self createPreparedCellForIndex: idx];
//[_visibleCells addObject: cell];
[self doAddVisibleCell: cell];
-
+
// tell the delegate
[self delegateWillDisplayCell: cell atIndex: idx];
-
+
idx = [insertedIndices indexGreaterThanIndex: idx];
}
}
-
+
if ( [_visibleCells count] > [newVisibleIndices count] )
{
//NSLog( @"Have to prune visible cell list, I've still got extra cells in there!" );
@@ -1694,7 +1697,7 @@ - (void) updateVisibleGridCellsNow
{
[animatingDestinationIndices addIndex: item.index];
}
-
+
NSMutableIndexSet * toRemove = [[NSMutableIndexSet alloc] init];
NSMutableIndexSet * seen = [[NSMutableIndexSet alloc] init];
NSUInteger i, count = [_visibleCells count];
@@ -1714,52 +1717,52 @@ - (void) updateVisibleGridCellsNow
[cell removeFromSuperview];
[toRemove addIndex: i];
}
-
+
[seen addIndex: cell.displayIndex];
}
-
+
// all removed from superview, just need to remove from the list now
[_visibleCells removeObjectsAtIndexes: toRemove];
[toRemove release];
[seen release];
}
-
+
if ( [_visibleCells count] < [newVisibleIndices count] )
{
NSLog( @"Visible cell list is missing some items!" );
-
+
NSMutableIndexSet * visibleSet = [[NSMutableIndexSet alloc] init];
for ( AQGridViewCell * cell in _visibleCells )
{
[visibleSet addIndex: cell.displayIndex];
}
-
+
NSMutableIndexSet * missingSet = [newVisibleIndices mutableCopy];
[missingSet removeIndexes: visibleSet];
[visibleSet release];
-
+
NSLog( @"Got %lu missing indices", (unsigned long)[missingSet count] );
-
+
NSUInteger idx = [missingSet firstIndex];
while ( idx != NSNotFound )
{
AQGridViewCell * cell = [self createPreparedCellForIndex: idx];
//[_visibleCells addObject: cell];
[self doAddVisibleCell: cell];
-
+
// tell the delegate
[self delegateWillDisplayCell: cell atIndex: idx];
-
+
idx = [missingSet indexGreaterThanIndex: idx];
}
-
+
[missingSet release];
}
-
+
// everything should match up now, so update the visible range
_visibleIndices.location = [newVisibleIndices firstIndex];
_visibleIndices.length = [newVisibleIndices count];
-
+
// layout these cells -- this will also sort the visible cell list
[self layoutAllCells];
}
@@ -1779,16 +1782,16 @@ - (void) updateVisibleGridCellsNow
{
if ( _reloadingSuspendedCount > 0 )
return;
-
+
_reloadingSuspendedCount++;
-
-
+
+
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSIndexSet * newVisibleIndices = [_gridData indicesOfCellsInRect: [self gridViewVisibleBounds]];
-
+
BOOL enableAnim = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled: NO];
-
+
@try
{
// a couple of simple tests
@@ -1797,13 +1800,13 @@ - (void) updateVisibleGridCellsNow
([newVisibleIndices countOfIndexesInRange: _visibleIndices] != _visibleIndices.length) )
{
//NSLog( @"\n\n----------BEGIN CELL UPDATES----------" );
-
+
// something has changed. Compute intersections and remove/add cells as required
NSIndexSet * currentVisibleIndices = [NSIndexSet indexSetWithIndexesInRange: _visibleIndices];
-
+
// index sets for removed and inserted items
NSIndexSet * removedIndices = nil, * insertedIndices = nil;
-
+
// handle the simple case first
// TODO: if we replace _visibleIndices with an index set, this comparison will have to change
if ( [currentVisibleIndices intersectsIndexesInRange: _visibleIndices] == NO )
@@ -1816,30 +1819,30 @@ - (void) updateVisibleGridCellsNow
removedIndices = [currentVisibleIndices aq_indexesOutsideIndexSet: newVisibleIndices];
insertedIndices = [newVisibleIndices aq_indexesOutsideIndexSet: currentVisibleIndices];
}
-
+
//NSLog( @"Removing indices: %@, inserting indices: %@", removedIndices, insertedIndices );
//NSLog( @"Visible cells count = %lu", (unsigned long)[_visibleCells count] );
-
+
if ( ([removedIndices count] != 0) || ([insertedIndices count] != 0) )
{
if ( [removedIndices count] != 0 )
{
NSMutableIndexSet * shifted = [removedIndices mutableCopy];
-
+
// get an index set for everything being removed relative to items' locations within the visible cell list
[shifted shiftIndexesStartingAtIndex: [removedIndices firstIndex] by: 0 - (NSInteger)_visibleIndices.location];
//NSLog( @"Removed indices relative to visible cell list: %@", shifted );
-
+
// pull out the cells for manipulation
NSArray * removedCells = [_visibleCells objectsAtIndexes: shifted];
-
+
// remove them from the visible list
[_visibleCells removeObjectsAtIndexes: shifted];
//NSLog( @"After removals, visible cells count = %lu", (unsigned long)[_visibleCells count] );
-
+
// don't need this any more
[shifted release]; shifted = nil;
-
+
// remove cells from the view hierarchy -- but only if they're not being animated by something else
NSArray * animating = [[self.animatingCells valueForKey: @"animatingView"] allObjects];
if ( [animating firstObjectCommonWithArray: removedCells] != nil )
@@ -1849,21 +1852,21 @@ - (void) updateVisibleGridCellsNow
removedCells = [[mutable copy] autorelease];
[mutable release];
}
-
+
//NSLog( @"Removing %lu cells from screen", (unsigned long)[removedCells count] );
[removedCells makeObjectsPerformSelector: @selector(removeFromSuperview)];
-
+
// put them into the cell reuse queue
[self enqueueReusableCells: removedCells];
}
-
+
if ( [insertedIndices count] != 0 )
{
// now we do the insertions
NSUInteger first = [newVisibleIndices firstIndex];
NSLog( @"New starting index = %lu", (unsigned long)first );
NSLog( @"Visible cell count = %lu", (unsigned long)[_visibleCells count] );
-
+
// if there are cells being animated into place, skip them-- the animation has them already
if ( self.animatingCells.count != 0 )
{
@@ -1873,27 +1876,27 @@ - (void) updateVisibleGridCellsNow
// remove each animating item from the list we'll insert
[tmp removeIndex: item.index];
}
-
+
insertedIndices = [[tmp copy] autorelease];
[tmp release];
}
-
+
NSUInteger idx = [insertedIndices firstIndex];
while ( idx != NSNotFound )
{
AQGridViewCell * cell = [self createPreparedCellForIndex: idx];
[self delegateWillDisplayCell: cell atIndex: idx];
-
+
NSLog( @"Inserting cell for index %lu at visible list index %lu", (unsigned long)idx, (unsigned long)(idx - first) );
[_visibleCells insertObject: cell atIndex: idx-first];
-
+
idx = [insertedIndices indexGreaterThanIndex: idx];
}
}
-
+
// sort the visible cell list so everything is in global-index order
[self sortVisibleCellList];
-
+
// remove anything from _visibleCells whose index isn't in the visible range
NSMutableIndexSet * removeVisibleCells = [[NSMutableIndexSet alloc] init];
NSUInteger i = 0;
@@ -1903,34 +1906,34 @@ - (void) updateVisibleGridCellsNow
[removeVisibleCells addIndex: i];
i++;
}
-
+
if ( [removeVisibleCells count] != 0 )
{
NSLog( @"Missed some cells which need to be pruned from the visible cell list: %@", removeVisibleCells );
[_visibleCells removeObjectsAtIndexes: removeVisibleCells];
}
-
+
[removeVisibleCells release];
-
+
if ( [_visibleCells count] < [newVisibleIndices count] )
{
// some items are missing-- stick them in
-
+
}
-
+
// this assertion is only valid if we have ownership of everything on screen
// if an animation is going on, then some cells are owned by the animation list instead
if ( self.animatingCells.count == 0 )
NSAssert( [_visibleCells count] == [newVisibleIndices count], @"Cell count doesn't match what was expected" );
-
+
// need to have _visibleIndices setup before calling layout
_visibleIndices.location = [newVisibleIndices firstIndex];
_visibleIndices.length = [newVisibleIndices count];
-
+
// layout the new cells
[self layoutCellsInVisibleCellRange: NSMakeRange(0, [_visibleCells count])];
}
-
+
//NSLog( @"----------END CELL UPDATES----------\n\n" );
}
}
@@ -1947,18 +1950,18 @@ - (void) updateVisibleGridCellsNow
{
if ( _reloadingSuspendedCount > 0 )
return;
-
+
if ( _flags.isAnimatingUpdates || _flags.updating )
return;
-
+
_reloadingSuspendedCount++;
NSIndexSet * newVisibleIndices = [_gridData indicesOfCellsInRect: [self gridViewVisibleBounds]];
-
+
NSUInteger beforeTest = (_visibleIndices.location == 0 ? NSNotFound : _visibleIndices.location - 1);
NSUInteger afterTest = MIN(_visibleIndices.location+_visibleIndices.length, _gridData.numberOfItems);
-
+
//NSLog( @"New Visible Indices = %@, _visibleIndices = %@", newVisibleIndices, NSStringFromRange(_visibleIndices) );
-
+
// do we need to remove anything?
if ( [newVisibleIndices countOfIndexesInRange: _visibleIndices] < _visibleIndices.length )
{
@@ -1971,42 +1974,42 @@ - (void) updateVisibleGridCellsNow
BOOL removeFromFront = NO;
if ( [indicesToRemove containsIndex: _visibleIndices.location] )
removeFromFront = YES;
-
+
NSUInteger numToRemove = [indicesToRemove count];
NSRange arrayRange = {0, 0};
if ( removeFromFront )
arrayRange = NSMakeRange(0, numToRemove);
else
arrayRange = NSMakeRange([_visibleCells count] - numToRemove, numToRemove);
-
+
//NSLog( @"Removing cells in visible range: %@", NSStringFromRange(arrayRange) );
-
+
// grab the removed cells (retains them)
NSMutableArray * removedCells = [[[_visibleCells subarrayWithRange: arrayRange] mutableCopy] autorelease];
-
+
// don't remove cells which are animating right now
if ( self.animatingCells.count != 0 )
{
[removedCells removeObjectsInArray: self.animatingCells];
numToRemove = [removedCells count];
arrayRange.length = numToRemove;
}
-
+
// remove from the visible list
[_visibleCells removeObjectsInRange: arrayRange];
-
+
// trim the visible cell index range
_visibleIndices.length -= numToRemove;
-
+
if ( removeFromFront )
_visibleIndices.location += numToRemove;
-
+
// remove cells from superview
[removedCells makeObjectsPerformSelector: @selector(removeFromSuperview)];
-
+
// put them into the recycled cell list
[self enqueueReusableCells: removedCells];
-
+
// done removing cells
}
else
@@ -2015,16 +2018,16 @@ - (void) updateVisibleGridCellsNow
NSMutableArray * removedCells = [[_visibleCells mutableCopy] autorelease];
if ( self.animatingCells.count != 0 )
[removedCells removeObjectsInArray: self.animatingCells];
-
+
// remove any cells which aren't animating to new positions
[_visibleCells removeObjectsInArray: removedCells];
[removedCells makeObjectsPerformSelector: @selector(removeFromSuperview)];
[self enqueueReusableCells: removedCells];
-
+
// update visible indices as appropriate-- brute force this time
_visibleIndices.location = [newVisibleIndices firstIndex];
_visibleIndices.length = [newVisibleIndices count];
-
+
// load the new cells
NSUInteger idx = [newVisibleIndices firstIndex];
while ( idx != NSNotFound )
@@ -2034,56 +2037,56 @@ - (void) updateVisibleGridCellsNow
[_visibleCells addObject: cell];
idx = [newVisibleIndices indexGreaterThanIndex: idx];
}
-
+
[self layoutCellsInVisibleCellRange: NSMakeRange(0, [_visibleCells count])];
-
+
// all done
}
-
+
[indicesToRemove release];
}
-
+
// no animations on automatic cell layout
[UIView setAnimationsEnabled: NO];
-
+
if ( (beforeTest != NSNotFound) && ([newVisibleIndices containsIndex: beforeTest]) )
{
// moving backwards
NSMutableIndexSet * newIndices = [[newVisibleIndices mutableCopy] autorelease];
-
+
// prune the ones we know about already, so we have a list of only the new ones
[newIndices removeIndexesInRange: _visibleIndices];
[newIndices removeIndexesInRange: _revealingIndices];
-
+
// insert any new cells, in reverse order (so we always insert at index zero)
NSUInteger idx = [newIndices lastIndex];
while ( idx != NSNotFound )
{
AQGridViewCell * cell = [self createPreparedCellForIndex: idx];
[self delegateWillDisplayCell: cell atIndex: idx];
[_visibleCells insertObject: cell atIndex: _revealingIndices.length];
-
+
idx = [newIndices indexLessThanIndex: idx];
}
-
+
// update the visibleCell index range
_visibleIndices.length += [newIndices count];
_visibleIndices.location = [newVisibleIndices firstIndex];
-
+
// get the range of the new items
NSRange newCellRange = NSMakeRange([newIndices firstIndex], [newIndices lastIndex] - [newIndices firstIndex] + 1);
-
+
// map this range onto the current visible cell array
newCellRange.location = MIN(newCellRange.location - _visibleIndices.location, 0);
-
+
// now update their locations
[self layoutCellsInVisibleCellRange: newCellRange];
}
else if ( (NSLocationInRange(afterTest, _visibleIndices) == NO) && ([newVisibleIndices containsIndex: afterTest]) )
{
[self updateForwardCellsForVisibleIndices: newVisibleIndices];
}
-
+
[UIView setAnimationsEnabled: YES];
_reloadingSuspendedCount--;
}
@@ -2092,29 +2095,29 @@ - (void) updateVisibleGridCellsNow
- (void) layoutCellsInVisibleCellRange: (NSRange) range
{
NSParameterAssert(range.location + range.length <= [_visibleCells count]);
-
+
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-
+
NSArray * layoutList = [_visibleCells subarrayWithRange: range];
for ( AQGridViewCell * cell in layoutList )
{
if ( [_animatingIndices containsIndex: cell.displayIndex] )
continue; // don't adjust layout of something that is animating around
-
+
CGRect gridRect = [_gridData cellRectAtIndex: cell.displayIndex];
CGRect cellFrame = cell.frame;
-
+
cell.frame = [self fixCellFrame: cellFrame forGridRect: gridRect];
cell.selected = (cell.displayIndex == _selectedIndex);
}
-
+
[pool drain];
}
- (void) layoutAllCells
{
[self sortVisibleCellList];
-
+
NSRange range = NSMakeRange(0, _visibleIndices.length);
[self layoutCellsInVisibleCellRange: range];
}
@@ -2134,11 +2137,11 @@ - (CGRect) fixCellFrame: (CGRect) cellFrame forGridRect: (CGRect) gridRect
cellFrame.origin.x = gridRect.origin.x + floorf( (gridRect.size.width - cellFrame.size.width) * 0.5 );
cellFrame.origin.y = gridRect.origin.y + floorf( (gridRect.size.height - cellFrame.size.height) * 0.5 );
}
-
+
// let the delegate update it if appropriate
if ( _flags.delegateAdjustGridCellFrame )
cellFrame = [self.delegate gridView: self adjustCellFrame: cellFrame withinGridCellFrame: gridRect];
-
+
return ( cellFrame );
}
@@ -2149,14 +2152,14 @@ - (AQGridViewCell *) createPreparedCellForIndex: (NSUInteger) index usingGridDat
cell.separatorStyle = _flags.separatorStyle;
cell.editing = self.editing;
cell.displayIndex = index;
-
+
cell.frame = [self fixCellFrame: cell.frame forGridRect: [gridData cellRectAtIndex: index]];
if ( _backgroundView.superview == self )
[self insertSubview: cell aboveSubview: _backgroundView];
else
[self insertSubview: cell atIndex: 0];
[UIView setAnimationsEnabled: YES];
-
+
return ( cell );
}
@@ -2169,15 +2172,15 @@ - (void) insertVisibleCell: (AQGridViewCell *) cell atIndex: (NSUInteger) visibl
{
if ( visibleCellListIndex >= [_visibleCells count] )
return;
-
+
[_visibleCells insertObject: cell atIndex: visibleCellListIndex];
}
- (void) deleteVisibleCell: (AQGridViewCell *) cell atIndex: (NSUInteger) visibleCellListIndex appendingNewCell: (AQGridViewCell *) newCell
{
if ( visibleCellListIndex >= [_visibleCells count] )
return;
-
+
[_visibleCells removeObjectAtIndex: visibleCellListIndex];
//[_visibleCells addObject: newCell];
[self doAddVisibleCell: newCell];
@@ -2208,7 +2211,7 @@ - (void) viewDidRotate
{
if ( _reloadingSuspendedCount == 0 )
return;
-
+
if ( --_reloadingSuspendedCount == 0 )
[self updateVisibleGridCellsNow];
}
@@ -2231,15 +2234,15 @@ - (void) delegateWillDisplayCell: (AQGridViewCell *) cell atIndex: (NSUInteger)
{
edge |= AQGridViewCellSeparatorEdgeBottom;
}
-
+
cell.separatorEdge = edge;
}
-
+
//NSLog( @"Displaying cell at index %lu", (unsigned long) index );
-
+
if ( _flags.delegateWillDisplayCell == 0 )
return;
-
+
[self.delegate gridView: self willDisplayCell: cell forItemAtIndex: index];
}

0 comments on commit 150b372

Please sign in to comment.