In this episode, I cover how to implement Pull to Refresh on UITableView using an easy open source project called SSPullToRefresh, by Sam Soffes. I cover the basics, as well as creating a custom loading panel, drawn with Core Graphics.
Links Cheddar by Sam Soffes SSPullToRefresh Episode sample code Adding SSPullToRefresh to a UITableView First, you need to import the header and make your view controller conform to the delegate: #import "SSPullToRefresh.h" @interface MasterViewController : UITableViewController <SSPullToRefreshViewDelegate> @end Then declare a property for the component. This can be done in the header or in the implementation if you're using a class continuation. @property (nonatomic, strong) SSPullToRefreshView *pullToRefreshView; Then, in viewDidLoad... self.pullToRefreshView = [[SSPullToRefreshView alloc] initWithScrollView:self.tableView delegate:self]; Finally, implement some delegate methods: - (BOOL)pullToRefreshViewShouldStartLoading:(SSPullToRefreshView *)view { return YES; } - (void)pullToRefreshViewDidStartLoading:(SSPullToRefreshView *)view { [self refresh]; } - (void)pullToRefreshViewDidFinishLoading:(SSPullToRefreshView *)view { } And in our sample, we fake the network delay by using dispatch_after in the refresh method. double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_after(popTime, backgroundQueue, ^(void){ [_objects removeAllObjects]; for (int i = 0; i < 25; i++) { [self insertNewObject:nil]; } dispatch_async(dispatch_get_main_queue(), ^{ [self.pullToRefreshView finishLoading]; [self.tableView reloadData]; }); }); Creating a custom content view #import "SSPullToRefresh.h" @interface CustomPullToRefreshView : UIView <SSPullToRefreshContentView> @end The custom drawing of the 2 rectangles, based on the progress %: - (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); [[UIColor whiteColor] set]; CGContextFillRect(context, self.bounds); CGFloat width = self.bounds.size.width; CGFloat height = self.bounds.size.height; CGFloat barHeight = 10; CGFloat barWidth = (width / 2.0) * _progress; CGFloat barY = height - barHeight; CGRect leftRect = CGRectMake(0, barY, barWidth, barHeight); [_barColor set]; CGContextFillRect(context, leftRect); CGFloat rightX = width - barWidth; CGRect rightRect = CGRectMake(rightX, barY, barWidth, barHeight); CGContextFillRect(context, rightRect); } Next, make sure you conform to the SSPullToRefreshContentView protocol methods: - (void)setState:(SSPullToRefreshViewState)state withPullToRefreshView:(SSPullToRefreshView *)view { switch (state) { case SSPullToRefreshViewStateNormal: _barColor = [UIColor lightGrayColor]; break; case SSPullToRefreshViewStateLoading: [_indicator startAnimating]; _barColor = [UIColor colorWithRed:.7 green:1.0 blue:.7 alpha:1.0]; break; case SSPullToRefreshViewStateReady: _barColor = [UIColor greenColor]; break; case SSPullToRefreshViewStateClosing: [_indicator stopAnimating]; _barColor = [UIColor whiteColor]; break; default: break; } } - (void)setPullProgress:(CGFloat)pullProgress { _progress = pullProgress; [self setNeedsDisplay]; } Then wire it all up: self.pullToRefreshView.contentView = [[CustomPullToRefreshView alloc] init];