├── .gitattributes
├── gridview
├── en.lproj
│ ├── InfoPlist.strings
│ └── MainWindow.xib
├── gridview-Prefix.pch
├── main.m
├── gridviewAppDelegate.h
├── gridview-Info.plist
└── gridviewAppDelegate.m
├── gridview.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── project.pbxproj
├── .gitignore
├── JOGridViewCell.h
├── README.md
├── JOGridViewCell.m
├── JOGridView.h
└── JOGridView.m
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.m diff=objc
2 | *.mm diff=objc
3 |
--------------------------------------------------------------------------------
/gridview/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/gridview.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | build/*
3 | *.pbxuser
4 | !default.pbxuser
5 | *.mode1v3
6 | !default.mode1v3
7 | *.mode2v3
8 | !default.mode2v3
9 | *.perspectivev3
10 | !default.perspectivev3
11 | *.xcworkspace
12 | !default.xcworkspace
13 | !project.xcworkspace
14 | xcuserdata
15 | profile
16 | *.moved-aside
17 | .com.apple.timemachine.supported
--------------------------------------------------------------------------------
/gridview/gridview-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header for all source files of the 'gridview' target in the 'gridview' project
3 | //
4 |
5 | #import
6 |
7 | #ifndef __IPHONE_3_0
8 | #warning "This project uses features only available in iPhone SDK 3.0 and later."
9 | #endif
10 |
11 | #ifdef __OBJC__
12 | #import
13 | #import
14 | #endif
15 |
--------------------------------------------------------------------------------
/gridview/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // gridview
4 | //
5 | // Created by Jeremy Foo on 9/7/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | int main(int argc, char *argv[])
12 | {
13 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
14 | int retVal = UIApplicationMain(argc, argv, nil, nil);
15 | [pool release];
16 | return retVal;
17 | }
18 |
--------------------------------------------------------------------------------
/JOGridViewCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // JOGridViewCell.h
3 | // gridview
4 | //
5 | // Created by Jeremy Foo on 9/7/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface JOGridViewCell : UIView {
12 | NSString* __reuseIdentifier;
13 | UILabel* textLabel;
14 | }
15 | @property (readonly) UILabel *textLabel;
16 | @property (nonatomic, copy) NSString *reuseIdentifier;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/gridview/gridviewAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // gridviewAppDelegate.h
3 | // gridview
4 | //
5 | // Created by Jeremy Foo on 9/7/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "JOGridView.h"
11 |
12 | @interface gridviewAppDelegate : NSObject
13 |
14 | @property (nonatomic, retain) IBOutlet UIWindow *window;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | JOGridView
2 | ==========
3 |
4 | This is a grid view based on the concepts that UITableView set forth to provide.
5 |
6 | - A cell is one portion of a grid
7 | - Cells are bare now, need more features to pack it.
8 | - Cells are re-usable
9 | - The grid is defined by rows and columns
10 | - Rows have individually settable heights
11 | - Column widths are limited to the equal distribution amongst all columns in a row
12 | - There is no selection at this moment.
13 | - It automatically purges reusable cells when there is a memory constrain
14 |
15 | TODO:
16 | =====
17 | - clean up first before laying out to conserve on memory
18 | - consistent delegate/datasource method signatures
19 | - cellforrowatindexpath in JOGridView (wtf is it really for?)
20 | - reflow cells?
21 | - heightforrowatindexpath doesn't work before cache values are not done right when heightforrow is set dynamically (should cache using assoc storage)
--------------------------------------------------------------------------------
/JOGridViewCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // JOGridViewCell.m
3 | // gridview
4 | //
5 | // Created by Jeremy Foo on 9/7/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "JOGridViewCell.h"
10 |
11 | @implementation JOGridViewCell
12 | @synthesize reuseIdentifier = __reuseIdentifier;
13 | @synthesize textLabel;
14 |
15 | - (id)initWithFrame:(CGRect)frame
16 | {
17 | if ((self = [super initWithFrame:frame])) {
18 | // Initialization code
19 | self.clipsToBounds = YES;
20 |
21 | textLabel = [[UILabel alloc] initWithFrame:frame];
22 | textLabel.backgroundColor = [UIColor clearColor];
23 | textLabel.textColor = [UIColor blackColor];
24 | textLabel.textAlignment = UITextAlignmentCenter;
25 | textLabel.text = @"";
26 |
27 | [self addSubview:textLabel];
28 |
29 | }
30 | return self;
31 | }
32 |
33 | -(void) dealloc {
34 | [__reuseIdentifier release], __reuseIdentifier = nil;
35 | [textLabel release], textLabel = nil;
36 | [super dealloc];
37 | }
38 |
39 | -(void)layoutSubviews {
40 | textLabel.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
41 | }
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/gridview/gridview-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIconFile
12 |
13 | CFBundleIdentifier
14 | net.ornyx.${PRODUCT_NAME:rfc1034identifier}
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | ${PRODUCT_NAME}
19 | CFBundlePackageType
20 | APPL
21 | CFBundleShortVersionString
22 | 1.0
23 | CFBundleSignature
24 | ????
25 | CFBundleVersion
26 | 1.0
27 | LSRequiresIPhoneOS
28 |
29 | NSMainNibFile
30 | MainWindow
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/JOGridView.h:
--------------------------------------------------------------------------------
1 | //
2 | // JOGridView.h
3 | // gridview
4 | //
5 | // Created by Jeremy Foo on 9/7/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "JOGridViewCell.h"
11 |
12 | @class JOGridView;
13 |
14 | /// Delegate
15 |
16 | @protocol JOGridViewDelegate
17 | @optional
18 | -(void)willDisplayCell:(JOGridViewCell *)cell forGridView:(JOGridView *)gridView atIndexPath:(NSIndexPath *)indexPath;
19 | -(CGFloat)gridView:(JOGridView *)gridview heightForRow:(NSUInteger)row;
20 | @end
21 |
22 | /// Data Sources are required
23 |
24 | @protocol JOGridViewDataSource
25 | @required
26 | -(NSUInteger)rowsForGridView:(JOGridView *)gridView;
27 | -(NSUInteger)columnsForGridView:(JOGridView *)gridView;
28 | -(JOGridViewCell *)cellForGridView:(JOGridView *)gridView atIndexPath:(NSIndexPath *)indexPath;
29 | @end
30 |
31 | @interface JOGridView : UIScrollView {
32 |
33 | // debug
34 |
35 | BOOL debug;
36 | UILabel* debugInfoLabel;
37 |
38 | // cached data
39 |
40 | NSUInteger __rows;
41 | NSUInteger __columns;
42 |
43 | NSUInteger __firstWarpedInRow;
44 | CGFloat __firstWarpedInRowHeight;
45 | NSUInteger __lastWarpedInRow;
46 | CGFloat __lastWarpedInRowHeight;
47 |
48 | // ivar properties
49 |
50 | CGFloat __previousOffset;
51 | BOOL __dataSourceDirty;
52 |
53 | NSMutableArray* __visibleRows;
54 | NSMutableDictionary* __reusableViews;
55 |
56 | id gridViewDelegate;
57 | id gridViewDataSource;
58 | }
59 | @property (nonatomic, assign) id datasource;
60 | @property (nonatomic, assign) id delegate;
61 | @property (readwrite) BOOL debug;
62 |
63 | /// cell accessors
64 | @property (readonly) NSArray *visibleRows;
65 | -(NSArray *)indexPathsForVisibleCells;
66 | -(NSIndexPath *)indexPathForVisibleCell:(JOGridViewCell *)cell;
67 | -(JOGridViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath;
68 |
69 | /// scrolling
70 | -(void)scrollToRow:(NSUInteger)row animated:(BOOL)animated;
71 | -(void)scrollToIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated;
72 |
73 | /// gridview properties
74 | @property (readonly) NSUInteger numberOfRows;
75 | @property (readonly) NSUInteger numberOfColumns;
76 |
77 | /// reload methods
78 | -(void)reloadData;
79 | -(void)reloadRow:(NSUInteger)row;
80 | -(void)reloadCellAtIndexPath:(NSIndexPath *)indexPath;
81 | -(JOGridViewCell *)dequeueReusableCellWithIdenitifer:(NSString *)identifier;
82 |
83 | @end
84 |
--------------------------------------------------------------------------------
/gridview/gridviewAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // gridviewAppDelegate.m
3 | // gridview
4 | //
5 | // Created by Jeremy Foo on 9/7/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "gridviewAppDelegate.h"
10 |
11 | @implementation gridviewAppDelegate
12 |
13 | @synthesize window = _window;
14 |
15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
16 | {
17 | // Override point for customization after application launch.
18 | [self.window makeKeyAndVisible];
19 |
20 | [[UIApplication sharedApplication] setStatusBarHidden:YES];
21 |
22 | JOGridView *gridview = [[JOGridView alloc] initWithFrame:CGRectMake(0, 0, self.window.frame.size.width, self.window.frame.size.height)];
23 | [self.window addSubview:gridview];
24 | gridview.debug = YES;
25 | gridview.delegate = self;
26 | gridview.datasource = self;
27 |
28 | [gridview release];
29 |
30 | return YES;
31 | }
32 |
33 | - (void)applicationWillResignActive:(UIApplication *)application
34 | {
35 | /*
36 | Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
37 | Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
38 | */
39 | }
40 |
41 | - (void)applicationDidEnterBackground:(UIApplication *)application
42 | {
43 | /*
44 | Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
45 | If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
46 | */
47 | }
48 |
49 | - (void)applicationWillEnterForeground:(UIApplication *)application
50 | {
51 | /*
52 | Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
53 | */
54 | }
55 |
56 | - (void)applicationDidBecomeActive:(UIApplication *)application
57 | {
58 | /*
59 | Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
60 | */
61 | }
62 |
63 | - (void)applicationWillTerminate:(UIApplication *)application
64 | {
65 | /*
66 | Called when the application is about to terminate.
67 | Save data if appropriate.
68 | See also applicationDidEnterBackground:.
69 | */
70 | }
71 |
72 | #pragma mark -
73 | #pragma mark JOGridView Stuff
74 |
75 | -(NSUInteger)rowsForGridView:(JOGridView *)gridView {
76 | return 50;
77 | }
78 |
79 | -(NSUInteger)columnsForGridView:(JOGridView *)gridView {
80 | return 5;
81 | }
82 |
83 |
84 | -(CGFloat)gridView:(JOGridView *)gridview heightForRow:(NSUInteger)row {
85 | return 64.0;
86 | }
87 |
88 |
89 | -(JOGridViewCell *)cellForGridView:(JOGridView *)gridView atIndexPath:(NSIndexPath *)indexPath {
90 | static NSString *identifier = @"cell";
91 |
92 | JOGridViewCell *cell = [gridView dequeueReusableCellWithIdenitifer:identifier];
93 |
94 | if (!cell) {
95 | cell = [[[JOGridViewCell alloc] init] autorelease];
96 | cell.reuseIdentifier = @"cell";
97 | }
98 |
99 | return cell;
100 | }
101 |
102 | + (UIColor *) randomColor
103 | {
104 | // stolen from http://kwigbo.com/post/680994703/iphone-sdk-random-uicolor
105 | // because i was lazy to write my own
106 |
107 | CGFloat red = (CGFloat)random()/(CGFloat)RAND_MAX;
108 | CGFloat blue = (CGFloat)random()/(CGFloat)RAND_MAX;
109 | CGFloat green = (CGFloat)random()/(CGFloat)RAND_MAX;
110 | return [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
111 | }
112 |
113 | -(void)willDisplayCell:(JOGridViewCell *)cell forGridView:(JOGridView *)gridView atIndexPath:(NSIndexPath *)indexPath {
114 | cell.textLabel.text = [NSString stringWithFormat:@"%i:%i", indexPath.section, indexPath.row];
115 | cell.textLabel.backgroundColor = [gridviewAppDelegate randomColor];
116 | }
117 |
118 |
119 | - (void)dealloc
120 | {
121 | [_window release];
122 | [super dealloc];
123 | }
124 |
125 | @end
126 |
--------------------------------------------------------------------------------
/gridview/en.lproj/MainWindow.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 800
5 | 10D540
6 | 760
7 | 1038.29
8 | 460.00
9 |
13 |
17 |
21 |
30 |
31 | YES
32 |
33 | IBFilesOwner
34 | IBCocoaTouchFramework
35 |
36 |
37 | IBFirstResponder
38 | IBCocoaTouchFramework
39 |
40 |
41 | IBCocoaTouchFramework
42 |
43 |
44 |
45 | 1316
46 |
47 | {320, 480}
48 |
49 |
50 | 1
51 | MSAxIDEAA
52 |
53 | NO
54 | NO
55 |
56 | IBCocoaTouchFramework
57 | YES
58 |
59 |
60 |
61 |
62 | YES
63 |
64 |
65 | delegate
66 |
67 |
68 |
69 | 4
70 |
71 |
72 |
73 | window
74 |
75 |
76 |
77 | 5
78 |
79 |
80 |
81 |
82 | YES
83 |
84 | 0
85 |
86 |
87 |
88 |
89 |
90 | 2
91 |
92 |
93 | YES
94 |
95 |
96 |
97 |
98 | -1
99 |
100 |
101 | File's Owner
102 |
103 |
104 | 3
105 |
106 |
107 |
108 |
109 | -2
110 |
111 |
112 |
113 |
114 |
115 |
116 | YES
117 |
118 | YES
119 | -1.CustomClassName
120 | -2.CustomClassName
121 | 2.IBAttributePlaceholdersKey
122 | 2.IBEditorWindowLastContentRect
123 | 2.IBPluginDependency
124 | 3.CustomClassName
125 | 3.IBPluginDependency
126 |
127 |
128 | YES
129 | UIApplication
130 | UIResponder
131 |
132 | YES
133 |
134 |
135 | YES
136 |
137 |
138 | {{198, 376}, {320, 480}}
139 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
140 | gridviewAppDelegate
141 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
142 |
143 |
144 |
145 | YES
146 |
147 |
148 | YES
149 |
150 |
151 |
152 |
153 | YES
154 |
155 |
156 | YES
157 |
158 |
159 |
160 | 9
161 |
162 |
163 |
164 | YES
165 |
166 | gridviewAppDelegate
167 | NSObject
168 |
169 | window
170 | UIWindow
171 |
172 |
173 | IBProjectSource
174 | gridviewAppDelegate.h
175 |
176 |
177 |
178 | gridviewAppDelegate
179 | NSObject
180 |
181 | IBUserSource
182 |
183 |
184 |
185 |
186 |
187 | 0
188 | IBCocoaTouchFramework
189 |
190 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3
191 |
192 |
193 | YES
194 | gridview.xcodeproj
195 | 3
196 | 81
197 |
198 |
199 |
--------------------------------------------------------------------------------
/gridview.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 3FBB3E541417055F00588168 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3FBB3E531417055F00588168 /* UIKit.framework */; };
11 | 3FBB3E561417055F00588168 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3FBB3E551417055F00588168 /* Foundation.framework */; };
12 | 3FBB3E581417055F00588168 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3FBB3E571417055F00588168 /* CoreGraphics.framework */; };
13 | 3FBB3E5E1417055F00588168 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3FBB3E5C1417055F00588168 /* InfoPlist.strings */; };
14 | 3FBB3E601417055F00588168 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FBB3E5F1417055F00588168 /* main.m */; };
15 | 3FBB3E641417055F00588168 /* gridviewAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FBB3E631417055F00588168 /* gridviewAppDelegate.m */; };
16 | 3FBB3E671417055F00588168 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3FBB3E651417055F00588168 /* MainWindow.xib */; };
17 | 3FBB3E6F1417058700588168 /* JOGridView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FBB3E6E1417058700588168 /* JOGridView.m */; };
18 | 3FBB3E7514172B0100588168 /* JOGridViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FBB3E7414172B0100588168 /* JOGridViewCell.m */; };
19 | /* End PBXBuildFile section */
20 |
21 | /* Begin PBXFileReference section */
22 | 3FBB3E4F1417055F00588168 /* gridview.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = gridview.app; sourceTree = BUILT_PRODUCTS_DIR; };
23 | 3FBB3E531417055F00588168 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
24 | 3FBB3E551417055F00588168 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
25 | 3FBB3E571417055F00588168 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
26 | 3FBB3E5B1417055F00588168 /* gridview-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "gridview-Info.plist"; sourceTree = ""; };
27 | 3FBB3E5D1417055F00588168 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
28 | 3FBB3E5F1417055F00588168 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
29 | 3FBB3E611417055F00588168 /* gridview-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "gridview-Prefix.pch"; sourceTree = ""; };
30 | 3FBB3E621417055F00588168 /* gridviewAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = gridviewAppDelegate.h; sourceTree = ""; };
31 | 3FBB3E631417055F00588168 /* gridviewAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = gridviewAppDelegate.m; sourceTree = ""; };
32 | 3FBB3E661417055F00588168 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainWindow.xib; sourceTree = ""; };
33 | 3FBB3E6D1417058700588168 /* JOGridView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JOGridView.h; sourceTree = ""; };
34 | 3FBB3E6E1417058700588168 /* JOGridView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JOGridView.m; sourceTree = ""; };
35 | 3FBB3E7314172B0100588168 /* JOGridViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JOGridViewCell.h; sourceTree = ""; };
36 | 3FBB3E7414172B0100588168 /* JOGridViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JOGridViewCell.m; sourceTree = ""; };
37 | /* End PBXFileReference section */
38 |
39 | /* Begin PBXFrameworksBuildPhase section */
40 | 3FBB3E4C1417055F00588168 /* Frameworks */ = {
41 | isa = PBXFrameworksBuildPhase;
42 | buildActionMask = 2147483647;
43 | files = (
44 | 3FBB3E541417055F00588168 /* UIKit.framework in Frameworks */,
45 | 3FBB3E561417055F00588168 /* Foundation.framework in Frameworks */,
46 | 3FBB3E581417055F00588168 /* CoreGraphics.framework in Frameworks */,
47 | );
48 | runOnlyForDeploymentPostprocessing = 0;
49 | };
50 | /* End PBXFrameworksBuildPhase section */
51 |
52 | /* Begin PBXGroup section */
53 | 3FBB3E441417055F00588168 = {
54 | isa = PBXGroup;
55 | children = (
56 | 3FBB3E7314172B0100588168 /* JOGridViewCell.h */,
57 | 3FBB3E7414172B0100588168 /* JOGridViewCell.m */,
58 | 3FBB3E6D1417058700588168 /* JOGridView.h */,
59 | 3FBB3E6E1417058700588168 /* JOGridView.m */,
60 | 3FBB3E591417055F00588168 /* gridview */,
61 | 3FBB3E521417055F00588168 /* Frameworks */,
62 | 3FBB3E501417055F00588168 /* Products */,
63 | );
64 | sourceTree = "";
65 | };
66 | 3FBB3E501417055F00588168 /* Products */ = {
67 | isa = PBXGroup;
68 | children = (
69 | 3FBB3E4F1417055F00588168 /* gridview.app */,
70 | );
71 | name = Products;
72 | sourceTree = "";
73 | };
74 | 3FBB3E521417055F00588168 /* Frameworks */ = {
75 | isa = PBXGroup;
76 | children = (
77 | 3FBB3E531417055F00588168 /* UIKit.framework */,
78 | 3FBB3E551417055F00588168 /* Foundation.framework */,
79 | 3FBB3E571417055F00588168 /* CoreGraphics.framework */,
80 | );
81 | name = Frameworks;
82 | sourceTree = "";
83 | };
84 | 3FBB3E591417055F00588168 /* gridview */ = {
85 | isa = PBXGroup;
86 | children = (
87 | 3FBB3E621417055F00588168 /* gridviewAppDelegate.h */,
88 | 3FBB3E631417055F00588168 /* gridviewAppDelegate.m */,
89 | 3FBB3E651417055F00588168 /* MainWindow.xib */,
90 | 3FBB3E5A1417055F00588168 /* Supporting Files */,
91 | );
92 | path = gridview;
93 | sourceTree = "";
94 | };
95 | 3FBB3E5A1417055F00588168 /* Supporting Files */ = {
96 | isa = PBXGroup;
97 | children = (
98 | 3FBB3E5B1417055F00588168 /* gridview-Info.plist */,
99 | 3FBB3E5C1417055F00588168 /* InfoPlist.strings */,
100 | 3FBB3E5F1417055F00588168 /* main.m */,
101 | 3FBB3E611417055F00588168 /* gridview-Prefix.pch */,
102 | );
103 | name = "Supporting Files";
104 | sourceTree = "";
105 | };
106 | /* End PBXGroup section */
107 |
108 | /* Begin PBXNativeTarget section */
109 | 3FBB3E4E1417055F00588168 /* gridview */ = {
110 | isa = PBXNativeTarget;
111 | buildConfigurationList = 3FBB3E6A1417055F00588168 /* Build configuration list for PBXNativeTarget "gridview" */;
112 | buildPhases = (
113 | 3FBB3E4B1417055F00588168 /* Sources */,
114 | 3FBB3E4C1417055F00588168 /* Frameworks */,
115 | 3FBB3E4D1417055F00588168 /* Resources */,
116 | );
117 | buildRules = (
118 | );
119 | dependencies = (
120 | );
121 | name = gridview;
122 | productName = gridview;
123 | productReference = 3FBB3E4F1417055F00588168 /* gridview.app */;
124 | productType = "com.apple.product-type.application";
125 | };
126 | /* End PBXNativeTarget section */
127 |
128 | /* Begin PBXProject section */
129 | 3FBB3E461417055F00588168 /* Project object */ = {
130 | isa = PBXProject;
131 | buildConfigurationList = 3FBB3E491417055F00588168 /* Build configuration list for PBXProject "gridview" */;
132 | compatibilityVersion = "Xcode 3.2";
133 | developmentRegion = English;
134 | hasScannedForEncodings = 0;
135 | knownRegions = (
136 | en,
137 | );
138 | mainGroup = 3FBB3E441417055F00588168;
139 | productRefGroup = 3FBB3E501417055F00588168 /* Products */;
140 | projectDirPath = "";
141 | projectRoot = "";
142 | targets = (
143 | 3FBB3E4E1417055F00588168 /* gridview */,
144 | );
145 | };
146 | /* End PBXProject section */
147 |
148 | /* Begin PBXResourcesBuildPhase section */
149 | 3FBB3E4D1417055F00588168 /* Resources */ = {
150 | isa = PBXResourcesBuildPhase;
151 | buildActionMask = 2147483647;
152 | files = (
153 | 3FBB3E5E1417055F00588168 /* InfoPlist.strings in Resources */,
154 | 3FBB3E671417055F00588168 /* MainWindow.xib in Resources */,
155 | );
156 | runOnlyForDeploymentPostprocessing = 0;
157 | };
158 | /* End PBXResourcesBuildPhase section */
159 |
160 | /* Begin PBXSourcesBuildPhase section */
161 | 3FBB3E4B1417055F00588168 /* Sources */ = {
162 | isa = PBXSourcesBuildPhase;
163 | buildActionMask = 2147483647;
164 | files = (
165 | 3FBB3E601417055F00588168 /* main.m in Sources */,
166 | 3FBB3E641417055F00588168 /* gridviewAppDelegate.m in Sources */,
167 | 3FBB3E6F1417058700588168 /* JOGridView.m in Sources */,
168 | 3FBB3E7514172B0100588168 /* JOGridViewCell.m in Sources */,
169 | );
170 | runOnlyForDeploymentPostprocessing = 0;
171 | };
172 | /* End PBXSourcesBuildPhase section */
173 |
174 | /* Begin PBXVariantGroup section */
175 | 3FBB3E5C1417055F00588168 /* InfoPlist.strings */ = {
176 | isa = PBXVariantGroup;
177 | children = (
178 | 3FBB3E5D1417055F00588168 /* en */,
179 | );
180 | name = InfoPlist.strings;
181 | sourceTree = "";
182 | };
183 | 3FBB3E651417055F00588168 /* MainWindow.xib */ = {
184 | isa = PBXVariantGroup;
185 | children = (
186 | 3FBB3E661417055F00588168 /* en */,
187 | );
188 | name = MainWindow.xib;
189 | sourceTree = "";
190 | };
191 | /* End PBXVariantGroup section */
192 |
193 | /* Begin XCBuildConfiguration section */
194 | 3FBB3E681417055F00588168 /* Debug */ = {
195 | isa = XCBuildConfiguration;
196 | buildSettings = {
197 | ALWAYS_SEARCH_USER_PATHS = NO;
198 | ARCHS = "$(ARCHS_STANDARD_32_BIT)";
199 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
200 | COPY_PHASE_STRIP = NO;
201 | GCC_C_LANGUAGE_STANDARD = gnu99;
202 | GCC_DYNAMIC_NO_PIC = NO;
203 | GCC_OPTIMIZATION_LEVEL = 0;
204 | GCC_PREPROCESSOR_DEFINITIONS = (
205 | "DEBUG=1",
206 | "$(inherited)",
207 | );
208 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
209 | GCC_VERSION = com.apple.compilers.llvmgcc42;
210 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
211 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
212 | GCC_WARN_UNUSED_VARIABLE = YES;
213 | IPHONEOS_DEPLOYMENT_TARGET = 4.3;
214 | SDKROOT = iphoneos;
215 | };
216 | name = Debug;
217 | };
218 | 3FBB3E691417055F00588168 /* Release */ = {
219 | isa = XCBuildConfiguration;
220 | buildSettings = {
221 | ALWAYS_SEARCH_USER_PATHS = NO;
222 | ARCHS = "$(ARCHS_STANDARD_32_BIT)";
223 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
224 | COPY_PHASE_STRIP = YES;
225 | GCC_C_LANGUAGE_STANDARD = gnu99;
226 | GCC_VERSION = com.apple.compilers.llvmgcc42;
227 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
228 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
229 | GCC_WARN_UNUSED_VARIABLE = YES;
230 | IPHONEOS_DEPLOYMENT_TARGET = 4.3;
231 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
232 | SDKROOT = iphoneos;
233 | VALIDATE_PRODUCT = YES;
234 | };
235 | name = Release;
236 | };
237 | 3FBB3E6B1417055F00588168 /* Debug */ = {
238 | isa = XCBuildConfiguration;
239 | buildSettings = {
240 | GCC_C_LANGUAGE_STANDARD = c99;
241 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
242 | GCC_PREFIX_HEADER = "gridview/gridview-Prefix.pch";
243 | INFOPLIST_FILE = "gridview/gridview-Info.plist";
244 | PRODUCT_NAME = "$(TARGET_NAME)";
245 | WRAPPER_EXTENSION = app;
246 | };
247 | name = Debug;
248 | };
249 | 3FBB3E6C1417055F00588168 /* Release */ = {
250 | isa = XCBuildConfiguration;
251 | buildSettings = {
252 | GCC_C_LANGUAGE_STANDARD = c99;
253 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
254 | GCC_PREFIX_HEADER = "gridview/gridview-Prefix.pch";
255 | INFOPLIST_FILE = "gridview/gridview-Info.plist";
256 | PRODUCT_NAME = "$(TARGET_NAME)";
257 | WRAPPER_EXTENSION = app;
258 | };
259 | name = Release;
260 | };
261 | /* End XCBuildConfiguration section */
262 |
263 | /* Begin XCConfigurationList section */
264 | 3FBB3E491417055F00588168 /* Build configuration list for PBXProject "gridview" */ = {
265 | isa = XCConfigurationList;
266 | buildConfigurations = (
267 | 3FBB3E681417055F00588168 /* Debug */,
268 | 3FBB3E691417055F00588168 /* Release */,
269 | );
270 | defaultConfigurationIsVisible = 0;
271 | defaultConfigurationName = Release;
272 | };
273 | 3FBB3E6A1417055F00588168 /* Build configuration list for PBXNativeTarget "gridview" */ = {
274 | isa = XCConfigurationList;
275 | buildConfigurations = (
276 | 3FBB3E6B1417055F00588168 /* Debug */,
277 | 3FBB3E6C1417055F00588168 /* Release */,
278 | );
279 | defaultConfigurationIsVisible = 0;
280 | defaultConfigurationName = Release;
281 | };
282 | /* End XCConfigurationList section */
283 | };
284 | rootObject = 3FBB3E461417055F00588168 /* Project object */;
285 | }
286 |
--------------------------------------------------------------------------------
/JOGridView.m:
--------------------------------------------------------------------------------
1 | //
2 | // JOGridView.m
3 | // gridview
4 | //
5 | // Created by Jeremy Foo on 9/7/11.
6 | // Copyright 2011 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "JOGridView.h"
10 | #import
11 |
12 | #define JOGRIDVIEW_DEFAULT_ROW_HEIGHT 44.0
13 |
14 | @interface JOGridView (InternalMethods)
15 | -(void)enqueueReusableCellsForRow:(NSUInteger)row;
16 | -(void)enqueueReusableCell:(JOGridViewCell *)cell;
17 |
18 | -(void)purgeCells;
19 | -(void)buildCells;
20 |
21 | -(NSArray *)cellsForLayoutOfRow:(NSUInteger)row atHeight:(CGFloat)height;
22 | -(void)layoutRow:(NSUInteger)row atHeight:(CGFloat)height scrollingUp:(BOOL)scrollingUp;
23 | -(JOGridViewCell *)cellForlayoutAtIndexPath:(NSIndexPath *)indexPath atHeight:(CGFloat)height;
24 |
25 | -(CGFloat)heightRelativeToOriginForRow:(NSUInteger)row;
26 | -(NSUInteger)rowForHeightRelativeToOrigin:(CGFloat)height;
27 |
28 | // delegate datasource single point of entry
29 | -(CGFloat)delegateHeightForRow:(NSUInteger)row;
30 | -(JOGridViewCell *)dataSourceCellAtIndexPath:(NSIndexPath *)indexPath;
31 | -(void)delegateWillDisplayCell:(JOGridViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
32 |
33 | @end
34 |
35 | @implementation JOGridView
36 | @synthesize visibleRows = __visibleRows;
37 | @synthesize datasource = gridViewDataSource, delegate = gridViewDelegate;
38 | @synthesize numberOfRows = __rows, numberOfColumns = __columns;
39 | @synthesize debug;
40 |
41 | - (id)initWithFrame:(CGRect)frame {
42 | if ((self = [super initWithFrame:frame])) {
43 | __reusableViews = [[NSMutableDictionary alloc] initWithCapacity:0];
44 | __visibleRows = [[NSMutableArray alloc] initWithCapacity:0];
45 | __rows = 0;
46 | __previousOffset = 0.0;
47 |
48 | __dataSourceDirty = YES;
49 |
50 | __firstWarpedInRow = 0;
51 | __firstWarpedInRowHeight = 0.0;
52 |
53 | __lastWarpedInRow = 0;
54 | __lastWarpedInRowHeight = 0.0;
55 |
56 | self.alwaysBounceVertical = YES;
57 | self.showsVerticalScrollIndicator = YES;
58 | self.showsHorizontalScrollIndicator = NO;
59 |
60 | self.canCancelContentTouches = NO;
61 | self.clipsToBounds = YES;
62 | self.pagingEnabled = NO;
63 | self.scrollEnabled = YES;
64 |
65 | debugInfoLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, self.frame.size.height - 10 - 22.0, 100.0, 22.0)];
66 | debugInfoLabel.textAlignment = UITextAlignmentCenter;
67 | debugInfoLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
68 | debugInfoLabel.backgroundColor = [UIColor whiteColor];
69 | debugInfoLabel.textColor = [UIColor blackColor];
70 | debugInfoLabel.layer.cornerRadius = 5.0;
71 | debugInfoLabel.font = [UIFont systemFontOfSize:10.0];
72 |
73 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(conserveMemory:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
74 | }
75 |
76 | return self;
77 | }
78 |
79 | -(void)dealloc {
80 |
81 | [debugInfoLabel release], debugInfoLabel = nil;
82 | [[NSNotificationCenter defaultCenter] removeObserver:self];
83 | [__reusableViews release], __reusableViews = nil;
84 | [__visibleRows release], __visibleRows = nil;
85 | [super dealloc];
86 | }
87 |
88 | #pragma mark -
89 | #pragma mark Override Accessors
90 |
91 | -(void)setDatasource:(id)datasource {
92 | if (datasource != gridViewDataSource) {
93 | gridViewDataSource = datasource;
94 | __dataSourceDirty = YES;
95 | }
96 | }
97 |
98 | #pragma mark -
99 | #pragma mark View Layout and Maintainence
100 |
101 | -(void)purgeCells {
102 | [__visibleRows removeAllObjects];
103 | [__reusableViews removeAllObjects];
104 |
105 | for (UIView *view in self.subviews) {
106 | [view removeFromSuperview];
107 | }
108 | }
109 |
110 | -(void)buildCells {
111 | // figure out the visible rows
112 |
113 | __firstWarpedInRow = [self rowForHeightRelativeToOrigin:self.contentOffset.y];
114 | __firstWarpedInRowHeight = [self heightRelativeToOriginForRow:__firstWarpedInRow];
115 |
116 | // lets find the last row
117 | CGFloat adjustedOffset = self.contentOffset.y + (self.contentOffset.y - __firstWarpedInRowHeight);
118 | NSUInteger startrow = __firstWarpedInRow;
119 |
120 | while ((adjustedOffset < (self.contentOffset.y + self.frame.size.height)) && (startrow < __rows)) {
121 | adjustedOffset += [self delegateHeightForRow:startrow];
122 | startrow++;
123 | }
124 |
125 | __lastWarpedInRow = startrow-1;
126 | __lastWarpedInRowHeight = [self heightRelativeToOriginForRow:__lastWarpedInRow];
127 |
128 | if (__dataSourceDirty) {
129 | // if the data source is dirty, it means we must purge all existing
130 | // cells and recreate them in the view hierachy
131 |
132 | __dataSourceDirty = NO;
133 | [self purgeCells];
134 |
135 | JOGridViewCell *cell = nil;
136 | NSMutableArray *rowArray = nil;
137 |
138 | for (NSUInteger i=__firstWarpedInRow;i<__lastWarpedInRow+1;i++) {
139 |
140 | rowArray = [NSMutableArray arrayWithCapacity:__columns];
141 |
142 | for (NSUInteger q=0;q<__columns;q++) {
143 | cell = [self dataSourceCellAtIndexPath:[NSIndexPath indexPathForRow:q inSection:i]];
144 |
145 | [self delegateWillDisplayCell:cell atIndexPath:[NSIndexPath indexPathForRow:q inSection:i]];
146 |
147 | [rowArray addObject:cell];
148 |
149 | if (!cell.superview) {
150 | [self addSubview:cell];
151 | }
152 |
153 |
154 | cell.frame = CGRectMake(-CGFLOAT_MAX, -CGFLOAT_MAX, 0, 0);
155 | }
156 |
157 | [__visibleRows addObject:rowArray];
158 | }
159 |
160 | if (self.debug) {
161 | [self.superview addSubview:debugInfoLabel];
162 | } else {
163 | [debugInfoLabel removeFromSuperview];
164 | }
165 |
166 | } else {
167 |
168 | // as a precaution, move all cells into hiding position if datasource
169 | // is not dirty but we call a reload data
170 |
171 | for (UIView *view in self.subviews) {
172 | view.frame = CGRectMake(-CGFLOAT_MAX, -CGFLOAT_MAX, 0, 0);
173 | }
174 | }
175 |
176 | // layout the cells
177 |
178 | CGFloat startHeight = __firstWarpedInRowHeight;
179 | CGFloat rowHeight = 0.0;
180 | JOGridViewCell *cell = nil;
181 |
182 | for (NSUInteger i=0;i<[__visibleRows count];i++) {
183 | rowHeight = [self delegateHeightForRow:__firstWarpedInRow + i];
184 |
185 | for (NSUInteger q=0;q<[[__visibleRows objectAtIndex:i] count];q++) {
186 | cell = [[__visibleRows objectAtIndex:i] objectAtIndex:q];
187 |
188 | cell.frame = CGRectMake(q * (self.frame.size.width / __columns), startHeight, self.frame.size.width / __columns, rowHeight);
189 | }
190 |
191 | startHeight += rowHeight;
192 | }
193 |
194 | }
195 |
196 | -(NSArray *)cellsForLayoutOfRow:(NSUInteger)row atHeight:(CGFloat)height {
197 |
198 | JOGridViewCell *cell = nil;
199 |
200 | NSMutableArray *rowOfCells = [NSMutableArray arrayWithCapacity:__columns];
201 |
202 | for (NSUInteger i=0;i<__columns;i++) {
203 | cell = [self cellForlayoutAtIndexPath:[NSIndexPath indexPathForRow:i inSection:row] atHeight:height];
204 | [rowOfCells addObject:cell];
205 | }
206 |
207 | return rowOfCells;
208 |
209 | }
210 |
211 | -(void)layoutRow:(NSUInteger)row atHeight:(CGFloat)height scrollingUp:(BOOL)scrollingUp {
212 |
213 | NSArray *rowOfCells = [self cellsForLayoutOfRow:row atHeight:height];
214 |
215 | if (scrollingUp) {
216 | [__visibleRows addObject:rowOfCells];
217 | } else {
218 | [__visibleRows insertObject:rowOfCells atIndex:0];
219 | }
220 | }
221 |
222 | -(JOGridViewCell *)cellForlayoutAtIndexPath:(NSIndexPath *)indexPath atHeight:(CGFloat)height {
223 | JOGridViewCell *cell = [self dataSourceCellAtIndexPath:indexPath];
224 |
225 | NSAssert(cell != nil, @"Cells cannot be nil!");
226 |
227 | [self delegateWillDisplayCell:cell atIndexPath:indexPath];
228 |
229 | if (!cell.superview) {
230 | [self addSubview:cell];
231 | }
232 |
233 | cell.frame = CGRectMake(indexPath.row * (self.frame.size.width / __columns), height, self.frame.size.width / __columns, [self delegateHeightForRow:indexPath.section]);
234 | [cell layoutSubviews];
235 |
236 | return cell;
237 |
238 | }
239 |
240 | -(void)layoutSubviews {
241 | [super layoutSubviews];
242 |
243 | BOOL scrollingDownwards = (__previousOffset > self.contentOffset.y) ? YES : NO;
244 |
245 | if ([gridViewDataSource conformsToProtocol:@protocol(JOGridViewDataSource)]) {
246 |
247 | if (__dataSourceDirty) {
248 | [self reloadData];
249 | }
250 |
251 | if (self.debug) {
252 | NSUInteger cellcount = 0;
253 |
254 | for (id obj in self.subviews) {
255 | if ([obj isKindOfClass:[JOGridViewCell class]]) {
256 | cellcount++;
257 | }
258 | }
259 |
260 | debugInfoLabel.text = [NSString stringWithFormat:@"cells in view: %i", cellcount];
261 | }
262 |
263 | if ([gridViewDataSource conformsToProtocol:@protocol(JOGridViewDataSource)]) {
264 | if (scrollingDownwards) {
265 | // scrolling down
266 |
267 | // decide if we are even gonna warp in new rows
268 |
269 | while ((__firstWarpedInRow > 0) && (self.contentOffset.y <= __firstWarpedInRowHeight)) {
270 | // lets warp in a row!
271 | __firstWarpedInRowHeight -= [self delegateHeightForRow:__firstWarpedInRow];
272 | __firstWarpedInRow--;
273 |
274 | [self layoutRow:__firstWarpedInRow
275 | atHeight:__firstWarpedInRowHeight
276 | scrollingUp:NO];
277 |
278 | // decide if we need to warp out a row that's now hidden
279 |
280 | while (([__visibleRows count] > 0) && ((self.contentOffset.y + self.frame.size.height) <= __lastWarpedInRowHeight)) {
281 |
282 | [self enqueueReusableCellsForRow:__lastWarpedInRow];
283 | [__visibleRows removeLastObject];
284 |
285 | __lastWarpedInRowHeight -= [self delegateHeightForRow:__lastWarpedInRow];
286 | __lastWarpedInRow--;
287 | }
288 |
289 | // agressive enqueuing of anything below the supposedly
290 | // last visible row
291 | for (UIView *view in self.subviews) {
292 | if (([view isKindOfClass:[JOGridViewCell class]]) && (view.frame.origin.x >= 0) && (view.frame.origin.y > __lastWarpedInRowHeight + [self delegateHeightForRow:__lastWarpedInRow])) {
293 | [self enqueueReusableCell:(JOGridViewCell *)view];
294 | }
295 | }
296 |
297 | }
298 |
299 |
300 |
301 | } else {
302 | // scrolling up
303 |
304 |
305 | while ((__lastWarpedInRow < __rows-1) && ((self.contentOffset.y + self.frame.size.height) >= (__lastWarpedInRowHeight + [self delegateHeightForRow:__lastWarpedInRow]))) {
306 |
307 | __lastWarpedInRowHeight += [self delegateHeightForRow:__lastWarpedInRow];
308 | __lastWarpedInRow++;
309 |
310 | [self layoutRow:__lastWarpedInRow
311 | atHeight:__lastWarpedInRowHeight
312 | scrollingUp:YES];
313 |
314 | // deal with enqueueing
315 | while (([__visibleRows count] > 0) && (self.contentOffset.y >= (__firstWarpedInRowHeight + [self delegateHeightForRow:__firstWarpedInRow]))) {
316 |
317 | [self enqueueReusableCellsForRow:__firstWarpedInRow];
318 | [__visibleRows removeObjectAtIndex:0];
319 |
320 | __firstWarpedInRowHeight += [self delegateHeightForRow:__firstWarpedInRow];
321 | __firstWarpedInRow++;
322 |
323 | }
324 |
325 | for (UIView *view in self.subviews) {
326 | if (([view isKindOfClass:[JOGridViewCell class]]) && (view.frame.origin.x >= 0) && (view.frame.origin.y < __firstWarpedInRowHeight)) {
327 | [self enqueueReusableCell:(JOGridViewCell *)view];
328 | }
329 | }
330 |
331 | }
332 |
333 | }
334 | }
335 | }
336 |
337 | __previousOffset = self.contentOffset.y;
338 | }
339 |
340 | -(NSUInteger)rowForHeightRelativeToOrigin:(CGFloat)height {
341 |
342 | // find out the row that the current height represents all the way from the
343 | // origin of the content view. if the height is exactly the height of the
344 | // row or less than the height, it is that row
345 |
346 | if ([gridViewDelegate respondsToSelector:@selector(gridView:heightForRow:)]) {
347 |
348 | CGFloat calcheight = 0.0;
349 | int row=0;
350 |
351 | while (calcheight < height) {
352 | calcheight += [gridViewDelegate gridView:self heightForRow:row];
353 | row++;
354 | }
355 |
356 | if (calcheight > height) {
357 | return row-1;
358 | } else {
359 | return row;
360 | }
361 |
362 | } else {
363 |
364 | return (NSUInteger)(height / JOGRIDVIEW_DEFAULT_ROW_HEIGHT);
365 |
366 | }
367 | }
368 |
369 | -(CGFloat)heightRelativeToOriginForRow:(NSUInteger)row {
370 |
371 | // returns the height for the row accurate to its full height from the
372 | // origin to the end of the row.
373 |
374 | if ([gridViewDelegate respondsToSelector:@selector(gridView:heightForRow:)]) {
375 | CGFloat height = 0.0;
376 |
377 | for (NSUInteger i=0;i= __firstWarpedInRow) && (indexPath.section <= __lastWarpedInRow)) {
426 | cell = [[__visibleRows objectAtIndex:(indexPath.section - __firstWarpedInRow)] objectAtIndex:indexPath.row];
427 | } else {
428 | cell = [self dataSourceCellAtIndexPath:indexPath];
429 | }
430 |
431 | return cell;
432 | }
433 |
434 |
435 | #pragma mark -
436 | #pragma mark Scrolling to Cells
437 |
438 | -(void)scrollToRow:(NSUInteger)row animated:(BOOL)animated {
439 | if (row < __rows) {
440 | CGFloat heightForRow = [self heightRelativeToOriginForRow:row];
441 | [self scrollRectToVisible:CGRectMake(0, heightForRow, self.frame.size.width, [self delegateHeightForRow:row]) animated:animated];
442 | }
443 | }
444 |
445 | -(void)scrollToIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated {
446 | [self scrollToRow:indexPath.section animated:animated];
447 | }
448 |
449 |
450 | #pragma mark -
451 | #pragma mark Reloading stuff
452 |
453 | -(void)reloadData {
454 |
455 | if ([gridViewDataSource conformsToProtocol:@protocol(JOGridViewDataSource)]) {
456 |
457 | __rows = [gridViewDataSource rowsForGridView:self];
458 | __columns = [gridViewDataSource columnsForGridView:self];
459 |
460 | // gather total height
461 | CGFloat totalHeight = 0.0;
462 |
463 | if ([gridViewDelegate respondsToSelector:@selector(gridView:heightForRow:)]) {
464 | for (NSUInteger i=0;i<__rows;i++) {
465 | totalHeight += [gridViewDelegate gridView:self heightForRow:i];
466 | }
467 | } else {
468 | totalHeight = __rows * JOGRIDVIEW_DEFAULT_ROW_HEIGHT;
469 | }
470 |
471 | self.contentSize = CGSizeMake(self.frame.size.width, totalHeight);
472 |
473 | [self buildCells];
474 |
475 | } else {
476 | NSLog(@"Y U NO CONFIRM TO PROPER REQUIRED PROTOCOL?");
477 |
478 | }
479 |
480 | }
481 |
482 | -(void)reloadCellAtIndexPath:(NSIndexPath *)indexPath {
483 | if ((indexPath.section >= __firstWarpedInRow) && (indexPath.section <= __lastWarpedInRow)) {
484 | NSArray *cellsForVisibleRow = [__visibleRows objectAtIndex:indexPath.section - __firstWarpedInRow];
485 | JOGridViewCell *cellToRefresh = [cellsForVisibleRow objectAtIndex:indexPath.row];
486 |
487 | [self enqueueReusableCell:cellToRefresh];
488 |
489 | [self cellForlayoutAtIndexPath:indexPath atHeight:[self heightRelativeToOriginForRow:indexPath.row]];
490 | }
491 |
492 | }
493 |
494 | -(void)reloadRow:(NSUInteger)row {
495 | if ((row >= __firstWarpedInRow) && (row <= __lastWarpedInRow)) {
496 | [self enqueueReusableCellsForRow:row];
497 | [self cellsForLayoutOfRow:row atHeight:[self heightRelativeToOriginForRow:row]];
498 | }
499 | }
500 |
501 |
502 | #pragma mark -
503 | #pragma mark Reusable Views
504 |
505 | -(void)conserveMemory:(NSNotification *)notification {
506 |
507 | NSArray *reusuableCells = nil;
508 |
509 | for (id key in [__reusableViews keyEnumerator]) {
510 | reusuableCells = [__reusableViews objectForKey:key];
511 |
512 | for (JOGridViewCell *cell in reusuableCells) {
513 | [cell removeFromSuperview];
514 | }
515 | }
516 |
517 | [__reusableViews removeAllObjects];
518 | }
519 |
520 | -(JOGridViewCell *)dequeueReusableCellWithIdenitifer:(NSString *)identifier {
521 |
522 | NSMutableArray *stack = [__reusableViews objectForKey:identifier];
523 |
524 | if ([stack count] > 0) {
525 |
526 | JOGridViewCell *view = [stack objectAtIndex:0];
527 | [stack removeObjectAtIndex:0];
528 |
529 | return view;
530 | } else {
531 | return nil;
532 | }
533 | }
534 |
535 | -(void)enqueueReusableCellsForRow:(NSUInteger)row {
536 | if ((row >= __firstWarpedInRow) && (row <= __lastWarpedInRow)) {
537 | NSArray *rowToEnqueu = [__visibleRows objectAtIndex:row - __firstWarpedInRow];
538 |
539 | for (JOGridViewCell *cell in rowToEnqueu) {
540 | [self enqueueReusableCell:cell];
541 | }
542 | }
543 | }
544 |
545 | -(void)enqueueReusableCell:(JOGridViewCell *)cell {
546 |
547 | cell.frame = CGRectMake(-CGFLOAT_MAX, -CGFLOAT_MAX, 0, 0);
548 |
549 | if (cell.reuseIdentifier) {
550 | if ([__reusableViews objectForKey:cell.reuseIdentifier]) {
551 | [[__reusableViews objectForKey:cell.reuseIdentifier] addObject:cell];
552 |
553 | } else {
554 | NSMutableArray *array = [NSMutableArray arrayWithCapacity:0];
555 | [array addObject:cell];
556 | [__reusableViews setObject:array forKey:cell.reuseIdentifier];
557 | }
558 |
559 | } else {
560 | [cell removeFromSuperview];
561 | }
562 | }
563 |
564 |
565 | #pragma mark -
566 | #pragma mark Delegate/Datasource Methods
567 |
568 | // inspired by Peter Steinberger's article at
569 | // http://petersteinberger.com/2011/09/fast-and-elegant-delegation-in-objective-c/
570 | // keeps things clean
571 |
572 | -(CGFloat)delegateHeightForRow:(NSUInteger)row {
573 | if ([gridViewDelegate respondsToSelector:@selector(gridView:heightForRow:)]) {
574 | return [gridViewDelegate gridView:self heightForRow:row];
575 | } else {
576 | return JOGRIDVIEW_DEFAULT_ROW_HEIGHT;
577 | }
578 | }
579 |
580 | -(JOGridViewCell *)dataSourceCellAtIndexPath:(NSIndexPath *)indexPath {
581 | if ([gridViewDataSource respondsToSelector:@selector(cellForGridView:atIndexPath:)]) {
582 | return [gridViewDataSource cellForGridView:self atIndexPath:indexPath];
583 | } else {
584 | return nil;
585 | }
586 | }
587 |
588 | -(void)delegateWillDisplayCell:(JOGridViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
589 | if ([gridViewDelegate respondsToSelector:@selector(willDisplayCell:forGridView:atIndexPath:)]) {
590 | [gridViewDelegate willDisplayCell:cell forGridView:self atIndexPath:indexPath];
591 | }
592 | }
593 |
594 |
595 | @end
596 |
--------------------------------------------------------------------------------