I'm using the following code to create a UIRefreshControl:
- (void) viewDidLoad { [super viewDidLoad]; UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init]; [refreshControl addTarget:self action:@selector(doLoad) forControlEvents:UIControlEventValueChanged]; self.refreshControl = refreshControl; } - (void) doLoad { dispatch_async(dispatch_get_global_queue(0, 0), ^{ // Instead of sleeping, I do a webrequest here. [NSThread sleepForTimeInterval: 5]; dispatch_async(dispatch_get_main_queue(), ^{ [tableView reloadData]; [self.refreshControl endRefreshing]; }); }); }
It works great. If I navigate to my view, drag the table, the code runs and the data displays.
However, what I would like to do is have the view in the 'loading' state as soon as it appears (that way the user knows something is going on). I have tried adding the following:
- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self.refreshControl beginRefreshing]; }
But it does not seem to work. When I navigate to the view, it looks like a regular view (refresh control is not visible), plus when I try to pull the refresh control, it never finished loading.
Obviously I'm going about this the wrong way. Any suggestions on how I should handle this?
Try this:
- (void) viewWillAppear: (BOOL) animated { [super viewWillAppear: animated]; self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height); [self.refreshControl beginRefreshing]; // kick off your async refresh! [self doLoad]; }
Remember to call endRefreshing at some point!
EDIT to add full working sample:
This sample view controller, built and run in iOS6.1 as the root viewcontroller starts with the UIRefreshControl
already visible and animating when the app launches.
TSTableViewController.h
@interface TSTableViewController : UITableViewController @end
TSTableViewController.m
#import "TSTableViewController.h" @implementation TSTableViewController { NSMutableArray* _dataItems; } - (void) viewDidLoad { [super viewDidLoad]; self.refreshControl = [UIRefreshControl new]; [self.refreshControl addTarget: self action: @selector( onRefresh: ) forControlEvents: UIControlEventValueChanged]; } - (void) viewWillAppear:(BOOL)animated { [super viewWillAppear: animated]; self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height); [self.refreshControl beginRefreshing]; [self onRefresh: nil]; } - (void) onRefresh: (id) sender { double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ _dataItems = [NSMutableArray new]; for ( int i = 0 ; i < arc4random() % 100 ; i++ ) { CFUUIDRef uuid = CFUUIDCreate( NULL ); [_dataItems addObject: CFBridgingRelease(CFUUIDCreateString( NULL, uuid)) ]; CFRelease( uuid ); } [self.refreshControl endRefreshing]; [self.tableView reloadData]; }); } #pragma mark - Table view data source - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView { return 1; } - (NSInteger) tableView:(UITableView *) tableView numberOfRowsInSection: (NSInteger) section { return _dataItems.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: nil]; cell.textLabel.text = [_dataItems objectAtIndex: indexPath.row]; return cell; } @end
Manually modifying the contentOffset
is insecure and wrong and can lead to unexpected behavior in some cases. This solution works without touching the contentOffset
at all:
func showRefreshControl(show: Bool) { if show { refreshControl?.beginRefreshing() tableView.scrollRectToVisible(CGRectMake(0, 0, 1, 1), animated: true) } else { refreshControl?.endRefreshing() } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With