0

I have a UITableView, and it displays data received from a WiFi-connected device.

I want to do the fairly bog-standard gesture response of dragging a table down, then releasing it, to trigger an update.

I guess I could attach a swipe gesture recognizer to the table's substrate view, but I'm wondering if there is a way to intercept this gesture directly from the table itself.

META:

I've been looking through the various docs and whatnot. I haven't had to do this before, so I never gave it any thought. Now I see that I probably should have thought about it.

If this is an obvious solution, I don't mind being told so, as long as you help me to find the "obvious" remedy. I'll delete this question if it's a bad one.

However, I haven't found a solution, and I'm usually fairly good at that kind of thing.

UPDATE I changed the title to better reflect what I'm asking.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Chris Marshall
  • 4,910
  • 8
  • 47
  • 72
  • Have you looked into the Pull To Refresh a table view? – Douglas Feb 27 '15 at 15:28
  • Hmm... [this one?](http://www.appcoda.com/pull-to-refresh-uitableview-empty/) It may be how we ask the question... I'll dig deeper. Even if this is a dumb question, I may leave it up if it helps anyone. I don't have much shame. – Chris Marshall Feb 27 '15 at 15:31
  • Yes, something like that. I have implemented that many times in my table views. – Douglas Feb 27 '15 at 15:36
  • 1
    Why don't you implement the standard, built-in "pull-to-refresh" feature of `UITableView`? Why implement your own using a gesture? – rmaddy Feb 27 '15 at 15:50
  • I'm afraid @Tim has the right answer... there's a native way of doing it – wolffan Feb 27 '15 at 16:12
  • Well, I won't be able to add a UITableViewController on top of the one I already have (there's a reason for that I won't go into). That does sound like the best way. However, I'll be using the @Ian method. It does mean that I need to cast the UITableView to UIScrollView when I assign the scroller delegate, but it works perfectly, and is very, very simple. – Chris Marshall Feb 27 '15 at 17:13
  • Don't be afraid to `addChildViewController` in order to get this native `UITableViewController` functionality. Rolling your own is always more error-prone. @Tim's answer is much better than mine if you specifically want a "pull to refresh" functionality. Your original question title indicated that you might just want a generic pull-down. – Ian MacDonald Feb 27 '15 at 17:22
  • Oh, it's not that. I'm writing a tutorial, and this is the very simplest way to do it (least code). It's not against the rules, but I can't spend a bunch of time explaining it beyond simply doing this. – Chris Marshall Feb 27 '15 at 18:50
  • Don't use it at all. Pull-to-refresh and other revealing "hacks" are very bad UX. Not because people don't know how to pull but because they don't pull every day. And your searchbox can become forgotten. – Brian Cannard Apr 19 '17 at 18:32

3 Answers3

7

The totally native way to do it is to use a UITableViewController in your UIViewController, e.g.

{
    tableViewController = [[UITableViewController alloc] init];
    [tableViewController setTableView:myTableView];

    refreshControl = [[UIRefreshControl alloc] init];
    [tableViewController setRefreshControl:refreshControl];
    [refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];
}
Tim Kokesh
  • 879
  • 7
  • 10
1

If you add a UIScrollViewDelegate to your UITableView, you can respond to scrollViewDidScroll: events. A negative contentOffset.y value indicates that your user has pulled down at the top of your tableview.

Ian MacDonald
  • 13,472
  • 2
  • 30
  • 51
0

This is what I ended up doing. Even though it is not the most "legal" way to do things, it is still highly effective, and absurdly simple:

I set up a scrollview delegate trap, like so, and added it to the delegate class:

//*******************************************
// Reacts to the table's scroller being changed.
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
                     withVelocity:(CGPoint)velocity
              targetContentOffset:(inout CGPoint *)targetContentOffset {
#ifdef DEBUG
    NSLog ( @"MyViewController::scrollViewWillEndDragging:%@withVelocity:(%f,%f)targetContentOffset:(%f,%f)",scrollView,velocity.x, velocity.y, targetContentOffset->x, targetContentOffset->y );
#endif

    // We have to have had a "hard pull South" to trigger a refresh of the objects.
    if ( (velocity.y < 0) && ([scrollView contentOffset].y < -60) ) {
#ifdef DEBUG
        NSLog ( @"We will perform a new refresh." );
#endif
    }
}

The "-60" is because I'm looking for the best offset before I set it into a static.

Chris Marshall
  • 4,910
  • 8
  • 47
  • 72