TestsTested | ✗ |
LangLanguage | Obj-CObjective C |
License | MIT |
ReleasedLast Release | Mar 2017 |
Maintained by David Beck.
TNKRefreshControl is a replacement for UIRefreshControl that can be used with any UIScrollView and uses a more modern look.
To run the example project, clone the repo, and run pod install
from the Example directory first.
See the documentation for more details.
Instead of setting refreshControl on a UITableViewController, you create and set a TNKRefreshControl on any UIScrollView or UIScrollView subclass like UITableView.
self.tableView.tnk_refreshControl = [TNKRefreshControl new];
[self.tableView.tnk_refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];
From there, you can programatically activate the refresh control programatically with beginRefreshing
. When you have finished loading content, make sure to call endRefreshing
.
- (IBAction)refresh:(id)sender {
[self.tableView.tnk_refreshControl beginRefreshing];
[_objectSource loadNewObjects:^(NSArray *newDates) {
[self.tableView.tnk_refreshControl endRefreshing];
[self.tableView reloadData];
}];
}
UITableView
has a nasty habit of placing it's section headers below contentInset
. This causes floating section headers to appear lower than they should when the refresh control is active. Previously, TNKRefreshControl would use method swizzling to adjust the headers. However, for many user's of the framework, they are not using the refresh control with floating headers, but layoutSubviews
gets swizzled on UITableView
for everyone that includes the framework in their project.
If you still need the fix for floating headers, you can include this code in your project, along with JRSwizzle. Further, you must use -[UITableView dequeueReusableHeaderFooterViewWithIdentifier:]
(or the default header views) for this to work. See rdar://19489536 for more info.
@implementation UITableView (TNKRefreshControl)
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSError *error;
BOOL result = [[self class] jr_swizzleMethod:@selector(layoutSubviews) withMethod:@selector(TNK_layoutSubviews) error:&error];
if (!result || error) {
NSLog(@"Can't swizzle methods - %@", [error description]);
}
});
}
- (void)TNK_layoutSubviews
{
[self TNK_layoutSubviews]; // this will call layoutSubviews implementation, because we have exchanged them.
// UITableView has a nasty habbit of placing it's section headers below contentInset
// We aren't changing that behavior, just adjusting for the inset that we added
if (self.tnk_refreshControl.addedContentInset.top != 0.0) {
//http://b2cloud.com.au/tutorial/uitableview-section-header-positions/
const NSUInteger numberOfSections = self.numberOfSections;
const UIEdgeInsets contentInset = self.contentInset;
const CGPoint contentOffset = self.contentOffset;
const CGFloat sectionViewMinimumOriginY = contentOffset.y + contentInset.top - self.tnk_refreshControl.addedContentInset.top;
// Layout each header view
for(NSUInteger section = 0; section < numberOfSections; section++)
{
UIView* sectionView = [self headerViewForSection:section];
if(sectionView == nil)
continue;
const CGRect sectionFrame = [self rectForSection:section];
CGRect sectionViewFrame = sectionView.frame;
sectionViewFrame.origin.y = ((sectionFrame.origin.y < sectionViewMinimumOriginY) ? sectionViewMinimumOriginY : sectionFrame.origin.y);
// If it's not last section, manually 'stick' it to the below section if needed
if(section < numberOfSections - 1)
{
const CGRect nextSectionFrame = [self rectForSection:section + 1];
if(CGRectGetMaxY(sectionViewFrame) > CGRectGetMinY(nextSectionFrame))
sectionViewFrame.origin.y = nextSectionFrame.origin.y - sectionViewFrame.size.height;
}
[sectionView setFrame:sectionViewFrame];
}
}
}
@end
David Beck, [email protected]
TNKRefreshControl is available under the MIT license. See the LICENSE file for more info.