Permalink
Browse files

Added a couple performance improvements

  • Loading branch information...
1 parent db6118e commit f2248c1cd780979e5e9e07f05d69a6b759c7ebbf @camh committed Mar 1, 2010
Showing with 46 additions and 37 deletions.
  1. +1 −0 .gitignore
  2. +0 −2 CHGridLayout/CHGridLayout.h
  3. +2 −1 CHGridLayout/CHGridLayout.m
  4. +3 −3 CHGridView.h
  5. +27 −17 CHGridView.m
  6. +2 −8 CHImageTileView.m
  7. +9 −4 CHTileView.m
  8. +2 −2 README.markdown
View
@@ -1 +1,2 @@
.DS_Store
+tests/
@@ -42,7 +42,6 @@ static CHSectionRange CHSectionRangeMake(int start, int end){
float rowHeight;
float pixelMargin;
float sectionTitleHeight;
- BOOL dynamicallyResizeTilesToFillSpace;
}
@property (nonatomic, readonly) NSMutableArray *index;
@@ -55,7 +54,6 @@ static CHSectionRange CHSectionRangeMake(int start, int end){
@property (nonatomic) float preLoadMultiplier;
@property (nonatomic) float rowHeight;
@property (nonatomic) float sectionTitleHeight;
-@property (nonatomic) BOOL dynamicallyResizeTilesToFillSpace;
- (void)setSections:(int)sections;
- (void)setNumberOfTiles:(int)tiles ForSectionIndex:(int)section;
@@ -17,7 +17,7 @@
#define SLOW_DEVICE_PRELOAD 2.0f
@implementation CHGridLayout
-@synthesize index, justTiles, gridWidth, contentHeight, padding, perLine, preLoadMultiplier, rowHeight, sectionTitleHeight, dynamicallyResizeTilesToFillSpace;
+@synthesize index, justTiles, gridWidth, contentHeight, padding, perLine, preLoadMultiplier, rowHeight, sectionTitleHeight;
- (id)init{
if(self = [super init]){
@@ -96,6 +96,7 @@ - (void)setNumberOfTiles:(int)tiles ForSectionIndex:(int)section{
- (void)clearData{
[index removeAllObjects];
+ [justTiles removeAllObjects];
[sectionTitles removeAllObjects];
contentHeight = 0.0f;
}
View
@@ -53,7 +53,7 @@
BOOL isSlowDevice;
//settable properties
- BOOL dynamicallyResizeTilesToFillSpace;
+ BOOL centerTilesInGrid;
BOOL allowsSelection;
CGSize padding;
float preLoadMultiplier;
@@ -69,7 +69,7 @@
@property (nonatomic, assign) id<CHGridViewDataSource> dataSource;
@property (nonatomic, assign) id<CHGridViewDelegate,UIScrollViewDelegate> delegate;
-@property (nonatomic) BOOL dynamicallyResizeTilesToFillSpace;
+@property (nonatomic) BOOL centerTilesInGrid;
@property (nonatomic) BOOL allowsSelection;
@property (nonatomic) CGSize padding;
@property (nonatomic) float preLoadMultiplier;
@@ -90,6 +90,6 @@
- (void)scrollToTileAtIndexPath:(CHGridIndexPath)indexPath animated:(BOOL)animated;
- (void)deselectTileAtIndexPath:(CHGridIndexPath)indexPath;
-- (void)deselecSelectedTile;
+- (void)deselectSelectedTile;
@end
View
@@ -24,7 +24,7 @@ - (void)calculateSectionTitleOffset;
@end
@implementation CHGridView
-@synthesize dataSource, dynamicallyResizeTilesToFillSpace, allowsSelection, padding, preLoadMultiplier, rowHeight, perLine, sectionTitleHeight, shadowOffset, shadowColor, shadowBlur;
+@synthesize dataSource, centerTilesInGrid, allowsSelection, padding, preLoadMultiplier, rowHeight, perLine, sectionTitleHeight, shadowOffset, shadowColor, shadowBlur;
- (id)init{
return [self initWithFrame:CGRectZero];
@@ -50,7 +50,7 @@ - (id)initWithFrame:(CGRect)frame{
sections = 1;
allowsSelection = YES;
- dynamicallyResizeTilesToFillSpace = NO;
+ centerTilesInGrid = NO;
padding = CGSizeMake(10.0f, 10.0f);
rowHeight = 100.0f;
perLine = 5;
@@ -137,14 +137,13 @@ - (void)loadVisibleTileForIndexPath:(CHGridIndexPath)indexPath withRect:(CGRect)
CHTileView *tile = [dataSource tileForIndexPath:indexPath inGridView:self];
[tile setIndexPath:indexPath];
- [tile setBackgroundColor:self.backgroundColor];
[tile setSelected:NO];
[tile setShadowOffset:shadowOffset];
[tile setShadowColor:shadowColor];
[tile setShadowBlur:shadowBlur];
- if([[self delegate] respondsToSelector:@selector(sizeForTileAtIndex:inGridView:)] && !dynamicallyResizeTilesToFillSpace){
+ if([[self delegate] respondsToSelector:@selector(sizeForTileAtIndex:inGridView:)] && centerTilesInGrid){
CGSize size = [[self delegate] sizeForTileAtIndex:indexPath inGridView:self];
CGRect centeredRect = [layout centerRect:CGRectMake(0.0f, 0.0f, size.width, size.height) inLargerRect:r roundUp:NO];
centeredRect.origin.y += r.origin.y;
@@ -156,12 +155,14 @@ - (void)loadVisibleTileForIndexPath:(CHGridIndexPath)indexPath withRect:(CGRect)
[tile setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth)];
}
+ [tile setBackgroundColor:self.backgroundColor];
+
[self insertSubview:tile atIndex:0];
[visibleTiles addObject:tile];
}
- (void)reuseHiddenTiles{
- NSMutableArray *toReuse = [NSMutableArray array];
+ NSMutableArray *toReuse = [[NSMutableArray alloc] init];
CGRect b = self.bounds;
CGFloat contentOffsetY = self.contentOffset.y;
@@ -179,6 +180,7 @@ - (void)reuseHiddenTiles{
}
[visibleTiles removeObjectsInArray:toReuse];
+ [toReuse release];
}
- (void)removeSectionTitleNotInRange:(CHSectionRange)range{
@@ -201,7 +203,7 @@ - (void)reloadData{
[self removeAllSubviews];
[visibleTiles removeAllObjects];
[visibleSectionTitles removeAllObjects];
-
+
CGRect b = [self bounds];
if([dataSource respondsToSelector:@selector(numberOfSectionsInGridView:)]){
@@ -219,7 +221,6 @@ - (void)reloadData{
[layout setPreLoadMultiplier:preLoadMultiplier];
[layout setRowHeight:rowHeight];
[layout setSectionTitleHeight:sectionTitleHeight];
- [layout setDynamicallyResizeTilesToFillSpace:dynamicallyResizeTilesToFillSpace];
[layout setSections:sections];
int i;
@@ -233,7 +234,11 @@ - (void)reloadData{
[self setNeedsLayout];
maxReusable = ceilf((self.bounds.size.height / rowHeight) * perLine) * 2;
- [self setContentSize:CGSizeMake(b.size.width, [layout contentHeight])];
+
+ if([layout contentHeight] > b.size.height)
+ [self setContentSize:CGSizeMake(b.size.width, [layout contentHeight])];
+ else
+ [self setContentSize:CGSizeMake(b.size.width, b.size.height + 1.0)];
}
- (CHTileView *)dequeueReusableTileWithIdentifier:(NSString *)identifier{
@@ -260,26 +265,31 @@ - (void)layoutSubviews{
CGFloat pixelMargin = rowHeight * [layout preLoadMultiplier];
CGFloat firstY = (b.size.height + contentOffsetY + pixelMargin);
CGFloat secondY = contentOffsetY - pixelMargin;
+
+ BOOL hasSections = (sections > 1);
+
+ if(hasSections){
+ CHSectionRange sectionRange = [layout sectionRangeForContentOffset:contentOffsetY andHeight:b.size.height];
+ [self loadVisibleSectionTitlesForSectionRange:sectionRange];
+ [self calculateSectionTitleOffset];
+
+ }
for(CHGridLayoutTile *tile in [layout justTiles]){
CGRect r = [tile rect];
if(r.origin.y < firstY && r.origin.y + r.size.height > secondY){
[self loadVisibleTileForIndexPath:tile.indexPath withRect:r];
}
}
+
//if([[self delegate] respondsToSelector:@selector(visibleTilesChangedTo:)]) [[self delegate] visibleTilesChangedTo:visibleTiles.count];
-
- if(sections > 1){
- CHSectionRange sectionRange = [layout sectionRangeForContentOffset:contentOffsetY andHeight:b.size.height];
- [self loadVisibleSectionTitlesForSectionRange:sectionRange];
- [self calculateSectionTitleOffset];
- }
}
- (void)removeAllSubviews{
[visibleTiles makeObjectsPerformSelector:@selector(removeFromSuperview)];
[visibleSectionTitles makeObjectsPerformSelector:@selector(removeFromSuperview)];
+ [reusableTiles makeObjectsPerformSelector:@selector(removeFromSuperview)];
}
#pragma mark tiles accessor methods
@@ -357,7 +367,7 @@ - (void)deselectTileAtIndexPath:(CHGridIndexPath)indexPath{
}
}
-- (void)deselecSelectedTile{
+- (void)deselectSelectedTile{
if(selectedTile){
[self deselectTileAtIndexPath:selectedTile.indexPath];
selectedTile = nil;
@@ -378,8 +388,8 @@ - (void)setDataSource:(id<CHGridViewDataSource>)d{
dataSource = d;
}
-- (void)setDynamicallyResizeTilesToFillSpace:(BOOL)dynamically{
- dynamicallyResizeTilesToFillSpace = dynamically;
+- (void)setCenterTilesInGrid:(BOOL)b{
+ centerTilesInGrid = b;
[self setNeedsLayout];
}
View
@@ -25,20 +25,14 @@ - (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseId{
}
- (void)setImage:(UIImage *)i{
- if([image isEqual:i]) return;
-
[image release];
image = [i retain];
- [self setNeedsDisplay];
}
- (void)drawContentRect:(CGRect)rect{
CGContextRef c = UIGraphicsGetCurrentContext();
CGSize imageSize = [image size];
- [[UIColor darkGrayColor] set];
- CGContextFillRect(c, rect);
-
float newWidth = 0.0f;
float newHeight = 0.0f;
float leftOffset = rect.origin.x;
@@ -78,8 +72,8 @@ - (void)drawContentRect:(CGRect)rect{
CGContextClipToRect(c, borderRect);
- CGContextSetStrokeColorWithColor(c, [[UIColor colorWithWhite:1.0f alpha:0.15f] CGColor]);
- CGContextStrokeRectWithWidth(c, rect, 4.0f);
+ //CGContextSetStrokeColorWithColor(c, [[UIColor colorWithWhite:1.0f alpha:0.15f] CGColor]);
+ //CGContextStrokeRectWithWidth(c, rect, 4.0f);
CGContextSetStrokeColorWithColor(c, [[UIColor colorWithWhite:0.0f alpha:0.4f] CGColor]);
CGContextStrokeRectWithWidth(c, rect, 2.0f);
View
@@ -19,13 +19,13 @@ - (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseId{
selected = NO;
reuseIdentifier = [reuseId copy];
- contentBackgroundColor = [[UIColor whiteColor] retain];
+ if(contentBackgroundColor == nil)
+ contentBackgroundColor = [[UIColor whiteColor] retain];
shadowOffset = CGSizeMake(0.0f, 0.0f);
shadowColor = [[UIColor colorWithWhite:0.0f alpha:0.5f] retain];
shadowBlur = 0.0f;
- [self setBackgroundColor:[UIColor whiteColor]];
[self setOpaque:YES];
[self setContentMode:UIViewContentModeRedraw];
}
@@ -49,13 +49,18 @@ - (void)unselect{
- (void)setIndexPath:(CHGridIndexPath)index{
indexPath = index;
- [self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect{
CGContextRef c = UIGraphicsGetCurrentContext();
- CGSize newShadowOffset = shadowOffset;
+ CGSize newShadowOffset;
+
+ #ifdef __IPHONE_3_2
+ newShadowOffset = CGSizeMake(shadowOffset.width, shadowOffset.height);
+ #else
+ newShadowOffset = CGSizeMake(shadowOffset.width, -shadowOffset.height);
+ #endif
CGRect contentRect = CGRectInset(rect, shadowBlur, shadowBlur);
if(newShadowOffset.height < 0) contentRect.size.height -= fabsf(newShadowOffset.height);
View
@@ -26,7 +26,7 @@ NOTICE: **CHGridView is not production-level software yet. Don't use it in shipp
Exactly like UITableView. Just implement the two required data source methods: `numberOfTilesInSection` and `tileForIndexPath`. CHGridView assumes there is at least one section. The method `tileForIndexPath` works very much like UITableView; CHGridView reuses tiles just like UITableView reuses cells. Call `dequeueReusableTileWithIdentifier` to get a reusable tile, if it's `nil`, `init` and `autorelease` a new tile and return it.
-There's two basic styles to use in GHGridView, one that resembles the Photos application, and one that mimics iPhoto and the iPad photo grid. The property that controls it is called `dynamicallyResizeTilesToFillSpace`. Set it to `YES` for the Photos app style.
+There's two basic styles to use in GHGridView, one that resembles the Photos application, and one that mimics iPhoto and the iPad photo grid. The property that controls it is called `centerTilesInGrid`. Set it to `YES` for the iPhoto style.
Row height, tiles per line, padding, section title height and shadow are all properties of CHGridView. These are not meant to change often like the data source and delegate methods. However, if you do change them, make sure to call `reloadData` to recalculate the layout.
@@ -59,7 +59,7 @@ If you disable scrolling with `setScrollingEnabled`, you can probably use this a
I've tested CHGridView informally with a test application on both my iPhones. For my data source, I used 31 images to populate 1,984 tiles separated with 64 sections. They were exported from iPhoto as PNGs with a maximum width of 160 pixels, then were drawn centered and cropped in CHImageTileView. Scrolling performance is not as good as Apple's Photos grid view, especially on my original iPhone.
-- Original iPhone: about 12 - 30 fps.
+- Original iPhone: about 18 - 35 fps.
- iPhone 3G3: about 30 - 50 fps.
Admittedly, performance could be better. If you see something that could be improved, send an email to [me@cameron.io](mailto:me@cameron.io).

0 comments on commit f2248c1

Please sign in to comment.