Latest 1.1.0
License MIT
Platforms ios 7.0, requires ARC

Carthage compatible

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];



TNKRefreshControl is available through CocoaPods. To install
it, simply add the following line to your Podfile:

pod "TNKRefreshControl", "~> 0.3"


Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.

You can install Carthage with Homebrew using the following command:

$ brew update
$ brew install carthage

To integrate TNKRefreshControl into your Xcode project using Carthage, specify it in your Cartfile:

github "davbeck/TNKRefreshControl" ~> 0.3

Run carthage to build the framework and drag the built TNKRefreshControl.framework into your Xcode project.

UITableView Floating Headers and updating from 0.6.0

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 ( != 0.0) {
        const NSUInteger numberOfSections = self.numberOfSections;
        const UIEdgeInsets contentInset = self.contentInset;
        const CGPoint contentOffset = self.contentOffset;

        const CGFloat sectionViewMinimumOriginY = contentOffset.y + -;

        //  Layout each header view
        for(NSUInteger section = 0; section < numberOfSections; section++)
            UIView* sectionView = [self headerViewForSection:section];

            if(sectionView == nil)

            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];



David Beck, [email protected]


TNKRefreshControl is available under the MIT license. See the LICENSE file for more info.

Latest podspec

    "name": "TNKRefreshControl",
    "version": "1.1.0",
    "summary": "A replacement for UIRefreshControl with a more modern look and more flexibility.",
    "homepage": "",
    "screenshots": [
    "license": "MIT",
    "authors": {
        "David Beck": "[email protected]"
    "source": {
        "git": "",
        "tag": "1.1.0"
    "social_media_url": "",
    "platforms": {
        "ios": "7.0"
    "requires_arc": true,
    "source_files": "TNKRefreshControl/*.{h,m}"

Pin It on Pinterest

Share This