Skip to content
Browse files

added pagination support, better sizing logic, automatic show/hide of…

… spinner.
  • Loading branch information...
1 parent 89412ed commit 2bd3240d223e920b6d2286a3d14295500c9a298b @ettore committed
Showing with 271 additions and 78 deletions.
  1. +53 −14 CLCGCell.h
  2. +56 −19 CLCGCell.m
  3. +73 −27 CLCGTVVC.h
  4. +89 −18 CLCGTVVC.m
View
67 CLCGCell.h
@@ -29,12 +29,21 @@
*/
-/**
- * This cell loads an image on the left side, renders multiline text in its
- * textLabel, adds a 1-line gray detailTextLabel and a standard disclosure
- * indicator on the right side. It also renders itself with a different
- * background color if it's set as a emphasized cell. The layout of
- * all components is performed accordingly, adding padding between elements.
+/*!
+ @abstract The max cell height used in layout calculations.
+ @discussion UIKit says that the max height of a cell should not exceed 2009px.
+ @see @link //apple_ref/occ/intfm/UITableViewDelegate/tableView:heightForRowAtIndexPath: @/link
+ */
+#define CLCG_MAX_CELL_H 2009.0f
+
+
+/*!
+ @class CLCGCell
+ @discussion This cell loads an image on the left side, renders multiline text
+ in its textLabel, adds a 1-line gray detailTextLabel and a standard disclosure
+ indicator on the right side. It also renders itself with a different
+ background color if it's set as a emphasized cell. The layout of
+ all components is performed accordingly, adding padding between elements.
*/
@interface CLCGCell : UITableViewCell
{
@@ -54,30 +63,60 @@
@property(nonatomic,retain) NSString *imgUrl;
@property(nonatomic,assign) BOOL emphasized;
@property(nonatomic,retain) id context;//should this be assign?
+@property(nonatomic,readonly) CGFloat padding;
-/** Designated initializer. */
+/*! Designated initializer. */
-(id)initWithImageWidth:(CGFloat)w
height:(CGFloat)h
padding:(CGFloat)padding
reuseId:(NSString*)cid;
-/** Calculates the height in accordance with all dependent parameters. */
-+(CGFloat)cellHeightForText:(NSString*)text
+/*!
+ @discussion Calculates the possible width available to the text label in any
+ CLCGCell, accounting for image width, accessory view, and padding.
+ */
++(CGFloat)textLabelWidthWithCellW:(CGFloat)maxw imageW:(CGFloat)w padding:(CGFloat)p;
+
+/*!
+ Calculates the height of the cell in accordance with all given parameters.
+ */
++(CGFloat)cellHeightForText:(NSString*)text
detailText:(NSString*)detailtext
font:(UIFont*)text_font
- detailFont:(UIFont*)detail_font
- cellMaxWidth:(CGFloat)cell_maxw
+ detailFont:(UIFont*)detail_font
+ maxWidth:(CGFloat)cell_maxw
imageW:(CGFloat)imgw
imageH:(CGFloat)imgh
padding:(CGFloat)padding;
-/** Changes the background color according to the current `isNew' state. */
+/*! Changes the background color according to the current `emphasized' state. */
-(void)updateBackgroundColor;
-/** Hides (or resets) the image to prevent flicker when scrolling fast. */
+/*!
+ @abstract Hides the image.
+ @discussion You might want to use this to prevent flicker when scrolling fast.
+*/
-(void)hideImage;
-/** Sets the image in the cell and shows it. */
+/*! Sets the image in the cell and shows it. */
-(void)showImage:(UIImage*)img;
+/*! The X position on the right of the image, considering padding. */
+-(CGFloat)xRightOfImage;
+
+/*!
+ @abstract The max width accounted during layout calculations for the
+ accessory view or discolosure arrow.
+ @discussion By default, CLCGCell does not use a true accessory view. Rather,
+ it employs the default UITableViewCellAccessoryDisclosureIndicator type.
+ If you use actual custom views for your accessory element, you should
+ probably create a subclass and override this method with actual
+ measurements.
+ @return A constant value that should account for the size of a default
+ accessory type.
+ */
++(CGFloat)maxAccessoryWidth;
+
+
@end
+
View
75 CLCGCell.m
@@ -36,9 +36,33 @@ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
#import "CLCGCell.h"
+/*!
+ @discussion Since we don't control the disclosure indicator size (and we need
+ to know the width when we calc the cell height in the TV controller) let's
+ provide a default size here, slightly bigger than actual to avoid
+ calculating a cell height that's too small.
+ HACK: this is fragile against future iterations of iOS.
+ TODO: find a way to derive the accessory width when we're not using a
+ custom accessory view.
+*/
+#define CLCG_DEFAULT_ACCESSORY_TYPE_W 22.0f
+
+
+/*!
+ @discussion This accounts for left and right viewport padding added by iOS,
+ since we are still using UITableViewCell for the layout of the image.
+ @note This is fragile in the sense that it could change in future releases
+ of iOS, but likely is not going to change by much more.
+ @todo Nevertheless, we should remove this dependency and just derive this
+ dynamically, although that can probably be done only at layout time
+ (typically we want to use this before layout, to calculate the height of
+ the cell.
+ */
+#define CLCG_DEFAULT_VIEWPORT_PADDING 11.0f
+
+/*! Construction time defaults. */
#define CLCGCELL_IMG_DEFAULT_W 60.0f
#define CLCGCELL_IMG_DEFAULT_H 60.0f
-#define MAX_CELL_H 20000.0f
@implementation CLCGCell
@@ -47,6 +71,7 @@ @implementation CLCGCell
@synthesize imgUrl = mImgUrl;
@synthesize context = mContext;
@synthesize emphasized = mEmphasized;
+@synthesize padding = mPadding;
-(void)dealloc
@@ -104,14 +129,6 @@ -(id)initWithImageWidth:(CGFloat)w
[self setBackgroundView:bgview];
[bgview release];
- // HACK: this is pretty fragile against future iterations of iOS.
- // TODO: find a way to derive the accessory width without using a
- // custom accessory view.
- // since we don't control the disclosure indicator size (and we need to
- // know the width when we calc the cell height in the TV controller) let's
- // provide a default size here, slightly bigger than actual to avoid
- // calculating a cell height that's too small.
-#define CLCGCELL_ACCESSORY_DISCL_W 22.0
[self setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}
return self;
@@ -178,6 +195,10 @@ -(void)showImage:(UIImage*)img
}
+//------------------------------------------------------------------------------
+#pragma mark - Layout
+
+
-(void)layoutSubviews
{
CGRect r;
@@ -191,8 +212,8 @@ -(void)layoutSubviews
// layout text label
w = [[self imageView] w];
- x = [[self imageView] x] + w + mPadding;
- w = [CLCGCell textLabelWidthWithMax:[self w] imageW:w padding:mPadding];
+ x = [self xRightOfImage];
+ w = [CLCGCell textLabelWidthWithCellW:[self w] imageW:w padding:mPadding];
sz = CGSizeMake(w, [self h]);
sz = [[[self textLabel] text] sizeWithFont:mTextFont
constrainedToSize:sz
@@ -212,11 +233,25 @@ -(void)layoutSubviews
}
-+(CGFloat)textLabelWidthWithMax:(CGFloat)maxw
- imageW:(CGFloat)imgw
- padding:(CGFloat)pad
+-(CGFloat)xRightOfImage
+{
+ CGRect r = [[self imageView] frame];
+ return r.origin.x + r.size.width + mPadding;
+}
+
+
++(CGFloat)maxAccessoryWidth
+{
+ return CLCG_DEFAULT_ACCESSORY_TYPE_W;
+}
+
+
++(CGFloat)textLabelWidthWithCellW:(CGFloat)maxw
+ imageW:(CGFloat)imgw
+ padding:(CGFloat)pad
{
- return maxw - imgw - ((imgw > 0) ? pad:0) - pad*3 - CLCGCELL_ACCESSORY_DISCL_W;
+ return maxw - imgw - ((imgw>0) ? pad:0) - pad
+ - CLCG_DEFAULT_VIEWPORT_PADDING*2 - [self maxAccessoryWidth];
}
@@ -225,7 +260,7 @@ +(CGFloat)cellHeightForText:(NSString*)text
detailText:(NSString*)detailtext
font:(UIFont*)text_font
detailFont:(UIFont*)detail_font
- cellMaxWidth:(CGFloat)cell_maxw
+ maxWidth:(CGFloat)cell_maxw
imageW:(CGFloat)imgw
imageH:(CGFloat)imgh
padding:(CGFloat)padding
@@ -234,10 +269,12 @@ +(CGFloat)cellHeightForText:(NSString*)text
CGFloat label_w, h;
// adding mPadding for cell margins (L & R) and right margin of img
- label_w = [CLCGCell textLabelWidthWithMax:cell_maxw imageW:imgw padding:padding];
+ // Note: using `self` here seems necessary to properly invoke polymorphism on
+ // maxAccessoryWidth, called by textLabelWidthWithCellW:imageW:padding:.
+ label_w = [self textLabelWidthWithCellW:cell_maxw imageW:imgw padding:padding];
// measure main text size
- sz = CGSizeMake(label_w, MAX_CELL_H);
+ sz = CGSizeMake(label_w, CLCG_MAX_CELL_H);
sz = [text sizeWithFont:text_font
constrainedToSize:sz
lineBreakMode:UILineBreakModeWordWrap];
@@ -245,7 +282,7 @@ +(CGFloat)cellHeightForText:(NSString*)text
// add detail text size.
h += padding + [detailtext sizeWithFont:detail_font
- constrainedToSize:CGSizeMake(label_w, MAX_CELL_H)
+ constrainedToSize:CGSizeMake(label_w, CLCG_MAX_CELL_H)
lineBreakMode:UILineBreakModeWordWrap].height;
// add padding above and below cell content
View
100 CLCGTVVC.h
@@ -1,25 +1,49 @@
-//
-// CLCGTVVC.h
-// PostalChess
-//
-// Created by e p on 3/5/12.
-// Copyright (c) 2012 Cubelogic. All rights reserved.
-//
+/*
+ Copyright (c) 2012, Ettore Pasquini
+ Copyright (c) 2012, Cubelogic
+ 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 Cubelogic 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 FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+ */
-#import "CLCGVC.h"
+#import "CLCGVC.h"
-// used to deque cells in table-view
-#define CLCGTVVC_CID @"CLCGTVVC_CID"
-#define CLCGTVVC_MORE_CID @"CLCGTVVC_MORE_CID"
-// default number of items to be loaded in table-view
+/*! Default number of items to be loaded in table-view. */
#define PER_PAGE_DEFAULT 20
-/**
- * Recreates the functionality of a UITableViewController, putting the
- * tableView as a subview of [self view].
+/*!
+ @abstract Recreates the functionality of a UITableViewController and adds
+ handling of content downloaded from the network.
+ @discussion This view controller creates and configures the tableview
+ programmatically, handles showing a "currently loading" spinner screen,
+ adds pagination support. By default, only one section is supported.
+ @note This class puts the tableView as a subview of [self view] making
+ it easy to swap it out while downloading content from the net.
*/
@interface CLCGTVVC : CLCGVC<UITableViewDelegate,UITableViewDataSource>
{
@@ -40,32 +64,54 @@
@property(nonatomic,retain) IBOutlet UITableView *tableView;
@property(nonatomic,assign) int page;
@property(nonatomic,assign) int perPage;
-@property(nonatomic,assign) BOOL supportsPagination;
+@property(nonatomic,assign) BOOL supportsPagination; /*! Disabled by default */
@property(nonatomic,assign) int itemsTotal;
@property(nonatomic,assign) int itemsEnd;
@property(nonatomic,retain) NSString *moreButtonText;
-// still the designated initializer. Defaults style to UITableViewStylePlain.
+/*! Still the designated initializer. Defaults style to UITableViewStylePlain. */
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil;
-// use this if you don't use a nib
+/*! Use this if you don't use a nib. */
-(id)initWithStyle:(UITableViewStyle)style;
-// if a subclass does not use a nib file, you should call this method in your
-// loadView implementation to create the base view structure (this includes
-// a background view and a TableView on top of that. The reason why this is
-// NOT done inside a local loadView implementation is because UIKit prohibits
-// to override loadView if the actual class uses a nib file: since this is a
-// base class and subclasses MIGHT use a nib file, we leave the task of actually
-// building the views hierarchy up to the user (either as a nib or by calling
-// loadBaseView inside the actual loadView implementation).
+/*!
+ If a subclass does not use a nib file, you should call this method in your
+ loadView implementation to create the base view structure (this includes
+ a background view and a TableView on top of that. The reason why this is
+ NOT done inside a local loadView implementation is because UIKit prohibits
+ to override loadView if the actual class uses a nib file: since this is a
+ base class and subclasses MIGHT use a nib file, we leave the task of actually
+ building the views hierarchy up to the user (either as a nib or by calling
+ loadBaseView inside the actual loadView implementation).
+ */
-(void)loadBaseView;
-// deselects all currently selected rows.
+/*!
+ @discussion Subclasses should override this method and initiate here any
+ asynchronous server side call. The default implementation does nothing.
+ */
+-(void)loadFromServerIfNeeded;
+
+/*! Deselects all currently selected rows. */
-(void)deselectAll:(BOOL)animated;
+/*!
+ Creates a standard "More..." CLCGMoreCell using @link moreButtonText @/link
+ as its text.
+ */
-(UITableViewCell*)tableView:(UITableView*)tv moreButtonCellForRow:(NSIndexPath*)ip;
+/*!
+ @discussion Handles loading the next page in case pagination is supported
+ and the user tapped on the "more" row, otherwise calls
+ @link tableView::didSelectNormalRow: @/link
+ */
+-(void)tableView:(UITableView*)tv didSelectRowAtIndexPath:(NSIndexPath*)ip;
+
+/*! Does nothing by default. */
+-(void)tableView:(UITableView*)tv didSelectNormalRow:(NSIndexPath*)ip;
+
-(BOOL)isMoreRow:(NSIndexPath*)ip;
@end
View
107 CLCGTVVC.m
@@ -1,15 +1,38 @@
-//
-// CLCGTVVC.m
-// PostalChess
-//
-// Created by e p on 3/5/12.
-// Copyright (c) 2012 Cubelogic. All rights reserved.
-//
+/*
+ Copyright (c) 2012, Ettore Pasquini
+ Copyright (c) 2012, Cubelogic
+ 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 Cubelogic 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 FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+ */
#import "CLCGTVVC.h"
#import "CLCGMoreCell.h"
+#define CLCGTVVC_MORE_CID @"CLCGTVVC_MORE_CID"
@implementation CLCGTVVC
@@ -106,6 +129,24 @@ -(void)viewDidLoad
}
+-(void)viewWillAppear:(BOOL)animated
+{
+ [super viewWillAppear:animated];
+ switch ([self loadState]) {
+ case CLCG_LOADING:
+ [self showLoadingView:YES];
+ break;
+ default: {
+ UITableView *tv = [self tableView];
+ [self showLoadingView:NO];
+ if ([tv indexPathForSelectedRow])
+ [tv deselectRowAtIndexPath:[tv indexPathForSelectedRow] animated:YES];
+ break;
+ }
+ }
+}
+
+
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
@@ -113,6 +154,11 @@ -(void)viewDidAppear:(BOOL)animated
}
+-(void)loadFromServerIfNeeded
+{
+}
+
+
//-----------------------------------------------------------------------------
#pragma mark - UITableView behavior
@@ -156,26 +202,33 @@ -(BOOL)isMoreRow:(NSIndexPath*)ip
}
--(UITableViewCell*)tableView:(UITableView*)tv moreButtonCellForRow:(NSIndexPath*)ip
-{
- CLCGMoreCell *cell;
+//-----------------------------------------------------------------------------
+#pragma mark - UITableViewDelegate
- cell = (CLCGMoreCell*)[tv dequeueReusableCellWithIdentifier:CLCGTVVC_MORE_CID];
- if (cell == nil) {
- cell = [[CLCGMoreCell alloc] initReusingId:CLCGTVVC_MORE_CID withText:mMoreButtonText];
- [cell autorelease];
+-(void)tableView:(UITableView*)tv didSelectRowAtIndexPath:(NSIndexPath*)ip
+{
+ if ([self isMoreRow:ip] && [self supportsPagination]) {
+ CLCGMoreCell *more;
+
+ mPage++;
+ [self setLoadState:CLCG_OUTDATED];
+ [self loadFromServerIfNeeded];
+ more = (CLCGMoreCell *)[self tableView:tv moreButtonCellForRow:ip];
+ [more didStartRequestingMore];
+ } else {
+ [self tableView:tv didSelectNormalRow:ip];
}
+}
- if (mLoadState != CLCG_LOADING)
- [cell didStopRequestingMore];
- return cell;
+-(void)tableView:(UITableView*)tv didSelectNormalRow:(NSIndexPath*)ip
+{
}
//-----------------------------------------------------------------------------
-#pragma mark - UITableViewDataSource protocol
+#pragma mark - UITableViewDataSource
-(NSInteger)numberOfSectionsInTableView:(UITableView*)tv
@@ -199,6 +252,24 @@ -(UITableViewCell*)tableView:(UITableView*)tv cellForRowAtIndexPath:(NSIndexPath
}
+-(UITableViewCell*)tableView:(UITableView*)tv moreButtonCellForRow:(NSIndexPath*)ip
+{
+ CLCGMoreCell *cell;
+
+ cell = (CLCGMoreCell*)[tv dequeueReusableCellWithIdentifier:CLCGTVVC_MORE_CID];
+
+ if (cell == nil) {
+ cell = [[CLCGMoreCell alloc] initReusingId:CLCGTVVC_MORE_CID withText:mMoreButtonText];
+ [cell autorelease];
+ }
+
+ if (mLoadState != CLCG_LOADING)
+ [cell didStopRequestingMore];
+
+ return cell;
+}
+
+
//------------------------------------------------------------------------------
#pragma mark - Pagination Support

0 comments on commit 2bd3240

Please sign in to comment.
Something went wrong with that request. Please try again.