Quantcast
iOS 6 Pull-to-Refresh Tutorial | Lextech Global Services

Blog

News, tutorials, and analyses of all things related to enterprise mobile apps

iOS 6 Pull-to-Refresh Tutorial


Hello and welcome to another Lex Tutorial!

Today you are going to learn about a new feature in iOS 6, the pull-to-refresh control available for UITableViewControllers.

Some things to keep in mind with this new control are the following:

  • It’s only available for UITableViewControllers, not regular UITableView instances
  • Cannot customize the shape or design, only the tint color
  • Cannot be added via Interface Builder, only programmatically

These may change at some point in the future but for now you’ll have to work with them.

The best way to showcase this new control is to jump straight into Xcode and start a new project. Please do this and select the Master-Detail Application iOS template.

Click Next and use Refresher as the Product Name, enter your Organization Name and Company Identifier, make sure only iPhone is selected for Devices and only check the Automatic Reference Counting and Storyboards checkboxes.

Click Next one more time and select where to save the project.

The template is pretty standard, you have a storyboard file for iPhone with a Navigation Controller, a UITableViewController as its root controller and a UIViewController for when a cell is tapped in the table. You will also notice the appropriate subclasses for the table view controller and the view controller.

Open MasterViewController.m and delete all of the method implementations except for the following:

    • didReceiveMemoryWarning
    • numberOfSectionsInTableView:
    • tableView:numberOfRowsInSection:
    • tableView:cellForRowAtIndexPath:
    • prepareForSegue:sender: 

After you do this, go ahead and delete the _objects variable declared in the class extension and replace it with this property declaration:

@interface MasterViewController ()

@property (strong, nonatomic) NSArray *objects;

@end

You’re not going to let users add or remove items to the table in this project, only use the pull-to-refresh control to invert the sorting of the items. It’s for this reason that a property with a custom getter method will be easier to work with. Add this code inside your implementation block:

- (NSArray *)objects
{

     if (!_objects)
     {

          _objects = @[@”Argentina”, @”Australia”, @”Brazil”, @”Ecuador”, @”England”, @”Germany”, @”Italy”, @”Japan”, @”New Zealand”, @”United States”];
     }

     return _objects;
}

This initializes the objects array with the names of some countries ordered from A-Z. Before running the project you need to make a few changes in order to use this property. Update the following methods as shown:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.objects.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

     UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:@”Cell” forIndexPath:indexPath];

     cell.textLabel.text = self.objects[indexPath.row];

     return cell;
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
     if ([[segue identifier] isEqualToString:@”showDetail”])
     {
          NSIndexPath *indexPath = [self.tableView
indexPathForSelectedRow];

          [[segue destinationViewController]
setDetailItem:self.objects[indexPath.row]];
     }
}

All you’re doing here is using the property instead of the instance variable. This will, if necessary, create the objects array with the preloaded list of countries.

Go ahead and run the project on a device or the simulator and check out the results:

Sweet, the table view is looking just as expected albeit without any pull-to-refresh. How about tackling that next?

Go back to MasterViewController.m and add the following implementation for viewDidLoad:

- (void)viewDidLoad
{
[superviewDidLoad];

     UIRefreshControl *refreshControl = [[UIRefreshControl alloc]
init];
     refreshControl.tintColor = [UIColormagentaColor];
     self.refreshControl = refreshControl;
}

As mentioned before, the UIRefreshControl has to be created programmatically. You do the standard alloc and init, set the tint color (this is optional but I wanted to show you that it can be done) and assign it to the table view controller’s refreshControl property.

Run the project one more time and pull the table view down:

Yay! Things are looking good. But, umm, the activity indicator never really stops!

This is because you need to respond to the valueChanged control event on the refresh control. To do this, update viewDidLoad as follows:

- (void)viewDidLoad
{
[superviewDidLoad];

     UIRefreshControl *refreshControl = [[UIRefreshControl alloc]
init];
refreshControl.tintColor = [UIColormagentaColor];
[refreshControl addTarget:selfaction:@selector(changeSorting) forControlEvents:UIControlEventValueChanged];
self.refreshControl = refreshControl;

}

And to avoid a runtime crash when you pull-to-refresh, stub out the changeSorting method:

- (void)changeSorting
{

}

Once again run your project. Notice how you are still getting the endless activity indicator. To fix this, add the following property declaration in your class extension:

@property (assign, nonatomic) BOOL ascending;

And add this code to changeSorting:

- (void)changeSorting
{
NSSortDescriptor *sortDescriptor = [[NSSortDescriptoralloc]
initWithKey:nilascending:self.ascending];
NSArray *sortDescriptors = @[sortDescriptor];

     _objects = [_objects sortedArrayUsingDescriptors:sortDescriptors];

     _ascending = !_ascending;

     [self performSelector:@selector(updateTable) withObject:nil
afterDelay:1];
}

This code uses a sort descriptor to change the sort order of the array by using the BOOL property created a second ago. You also call a method named updateTable with a small delay that will handle reloading the table data and setting the refresh control to stop updating.

Add the implementation for that private method as shown:

- (void)updateTable
{

     [self.tableView reloadData];

     [self.refreshControl endRefreshing];
}

Super simple, right?

Go ahead and run the project one more time, pull the table view down and notice how the list of countries is now using the reverse sort order!

Hurray! Great job, you’ve just learned about an awesome new feature in iOS 6 that will surely help you when building your next great app.

I hope you’ve enjoyed this brief tutorial. Feel free to leave your comments, suggestions and feedback below.

Have a good one,

Feli :)

zp8497586rq

There are 16 comments .

Karanzee

How would you go about doing the “pull to x” as seen in yelp and CNN apps? Where you pull in the app, and for example, the main CNN top story gets bigger, and in Yelp, the picture of the POI fills the screen? Thank you for this tutorial though! :)

    Felipe Laso Marsetti —

    Hey Karanzee,

    To do that you would probably have to use both custom cells as well as overriding the table view’s scroll view methods. That way you can know when a user is scrolling down/up on the table view and can get the scroll values in order to enlarge a cell as seen in the CNN app.

    For other pull-to-refresh mechanisms and implementations, I suggest you check out Cocoa Controls. There are several there that replicate the functionality seen in apps like Tweetbot or Pulse and are very easy to implement.

Gaandu —

Nice tutorials

Giancarlo Leonio

Hi

Thank you for this tutorial on adding Pull to Refresh to a table view in iOS 6. I have an Pull to Refresh board on Verious with this post. I’d like to share it with anyone interested in learning how to add a refresh control to a table view. Please let me know if there’s anything I can add to make a more comprehensive resource for other developers.
http://www.verious.com/board/Giancarlo-Leonio/adding-a-pull-to-refresh-to-a-table-view-in-ios-6/#

@Veriously

Nikita Pestrov

Thank you for a great tutorial, it really helped me to make that control just in 5 minutes!

Himanshu Kansal —

Thanks for a great tutorial, how can i have refresh control on a ViewController where i have a UITableView? I tried using

UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
refreshControl.tintColor = [UIColor grayColor];
[refreshControl addTarget:self action:@selector(updateTable) forControlEvents:UIControlEventValueChanged];

[self.mapTableView addSubview:refreshControl];

But didn’t find anything to stop the refresh controller something like
[self.refreshControl endRefreshing];

Thanks in Advance.

-Himanshu

    Felipe Laso Marsetti —

    Hey Himanshu,

    Unfortunately, at the time of this writing and as of iOS 6.0, the UIRefreshControl is only supported in UITableViewControllers.

    Attempting to use them with a table view is not recommended or (technically) allowed. If you change your table view to be a table view controller, you will find a property called “refreshControl” that you can use to assign a UIRefreshControl you create and customize.

    Thank you for the post and I hope this helps you get around the issue.
    Feli :)

Blake —

Thanks for the information. Could not have been written any better. Worked like a champ.

Isuru

I did not know that there’s a native iOS control to accomplish pull-to-refresh. I thought it was such a tedious task until I came across your blogpost. Thank you very much for the short but informative tutorial. :)

Twinkle —

Thaaanks .. this is so clear and helpful

Rohit Kothari —

Hi I want to integrate this feature in my test automation scripts. Can I call this feature from Java code for testing.

    Felipe Laso Marsetti —

    Hey Rohit,

    I know there’s support for automated UI-testing within Instruments. I’m not 100% sure if that can be done via Java, or what tools/APIs you’d have to use to use to make it work. You built in UI testing features use Javascript so it shouldn’t be too difficult to setup.

    If you want more info on Automated UI Testing then I recommend this book by Jonathan Penn.

    Best of luck and thanks for visiting our blog :)
    Feli

Comments are closed

Copyright ©2013 Lextech Global Services. All Rights Reserved.