3

I'm using a basic Three20 TTTableViewController subclass which employs its own datasource and model.

The problem is that I cannot seem to use the scrollsToTop property of the table. This is a standard property for the table, inherited from UIScrollView and very commonly used.

I have tried all of the following, in numerous different locations/methods within my class:

self.tableView.scrollsToTop = YES;
[self.tableView setScrollsToTop:YES]


I have also tried overriding the method

- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView {
    return YES; 
}

All without success.

NB. To be clear, I am referring to the standard gesture of tapping on the status bar to scroll a visible table view to the top (i.e. first row).

Any help much appreciated!

imnk
  • 4,342
  • 3
  • 29
  • 31
  • Any luck yet? I've just discovered this in a project I'm working on. The table view appears to have it's delegate and scrollsToTop set correctly, but it doesn't work. – Ryan Booker May 12 '11 at 06:02
  • Check my answer below Ryan. Got it sorted now. Just had to move my code around a bit. – imnk Aug 01 '11 at 15:10

4 Answers4

3

There is some confusion

According to Apple documentation of UIScrollView :

scrollsToTop

A Boolean value that controls whether the scroll-to-top gesture is effective

This is just to tell scrollview that taping status bar will make view scroll to top.

What you are looking for is this UITableView method :

scrollToRowAtIndexPath:atScrollPosition:animated:

Scrolls the receiver until a row identified by index path is at a particular location on the screen.

With three20

Since you are using three20 what you want to do can be easily done thanks to its UITableView+Additions.h > - (void)scrollToFirstRow:(BOOL)animated

[self.tableView scrollToFirstRow:YES];

Without three20

If not using three20, here is how three20 does:

- (void)scrollToFirstRow:(BOOL)animated {
  if ([self numberOfSections] > 0 && [self numberOfRowsInSection:0] > 0) {
    NSIndexPath* indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    [self scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop
          animated:NO];
  }
}

Another way to do this

I think that would also work (untested), using UIScrollView directly, (extracted from three20 too):

- (void)scrollToTop:(BOOL)animated {
  [self setContentOffset:CGPointMake(0,0) animated:animated];
}

or :

[self.tableView setContentOffset:CGPointMake(0,0) animated:YES];
Vincent Guerci
  • 14,379
  • 4
  • 50
  • 56
  • I have edited my original question to be clearer regarding exactly what the problem is. It is the scrolling to top via the status bar tap gesture that I am concerned with here. Not programmatically scrolling the table. – imnk May 23 '11 at 10:24
  • Ah ok. Well. I'm using `three20` massively in many projects, and never encountered that issue. Just try the `TTCatalog` sample app, you will see... It is not even necessary to set this variable, since it is the default. Then I'm afraid this is related to your code, and without it, no one can help. Or maybe that was a three20 bug (which I doubt) that has been fixed since. – Vincent Guerci May 24 '11 at 09:25
  • i think that occurs when you add some fixed subviews to the tableview and/or resize the tableview... at least, that's what i'm experiencing. but no solution found so far. – denbec Jul 25 '11 at 15:03
  • So far @denbec you've provided the best insight into this issue. Might be a good idea to post your comment as an answer, since it does shed some good light on the issue. – imnk Jul 28 '11 at 13:47
  • @imnk could you have another scrollview (or derived/compositing class, like a UIWebView) that catch the event? My guess is that the view order (nesting/ responder chain) is responsible of this. – Vincent Guerci Jul 28 '11 at 17:47
  • @vincent good suggestion but nope, the tableview is the only UIScrollView onscreen at this point. The table view cells are very basic with ~4 subviews and a background view - all labels and imageviews. – imnk Jul 28 '11 at 21:01
  • 1
    could you dump your view tree? breakpoint in your view controller and in `gdb` run `po [[self view] recursiveDescription]` – Vincent Guerci Jul 29 '11 at 00:54
  • @vincent great suggestion! looking at the view hierarchy I noticed that there are TWO TABLEVIEWS! why this is, I do not know. just out of interest, I removed one of them and voila! my scroll to top works! I'll be posting this an answer to my question but am reluctant to do so until I find out why the second tableview has been added. The class is a straight-ahead subclass of TTTableViewController. I'm going to do some experimenting and then post my findings. thank you. – imnk Aug 01 '11 at 14:46
3


Thanks to Vincent G for pointing me in the right direction. It appears that the issue is to do with what code is called in the class's init and viewDidLoad methods.

I discovered that under the following conditions, two tableviews are added as subviews of the view controller's view:

  1. Making reference to the property tableView in the viewDidLoad method, e.g. [[self tableView] setTableHeaderView:]

  2. Building the dataSource of the table within the init / initWithStyle method.

With two UIScrollViews present, the scroll-to-top action does not work properly, as Vincent pointed out. I will file these findings as a bug with the Three20 guys but by following these steps it can at least be avoided for now.

Edit: It seems that this maybe due to the viewDidLoad method being called BEFORE the init in some cases. If reference is made to the tableview in the viewDidLoad, before it has been created, I think the class is creating one. The init will then make another one.

imnk
  • 4,342
  • 3
  • 29
  • 31
  • 2
    `viewDidLoad` is called whenever you call `self.view`, which **I bet** you do in your init call. You *should avoid building view at initialization time*. Keep `init` for simple initializations, (like retrieving arguments, model data...) and use `loadView` for anything view-related. **Keep in mind that your view can be unloaded when memory is low, and then *automatically reloaded (=`loadView`)* at next appear**. That's why `init` is clearly separated from `loadView`... and not a three20 bug, an iOS design choice that makes sense for memory usage... Give a look at memory management of iOS. – Vincent Guerci Aug 02 '11 at 10:23
  • Thanks for the answer, it's been annoying me for months! Just moving self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; from the init to the viewDidLoad fixed the issue for me. Thanks again much appreciated. – Eamonn Fallon Aug 11 '11 at 02:55
1

try this:

self.tableview.scrollingEnabled=YES;
self.tableview.scrollsToTop=YES;

Also check that your delegate is returning YES in this method:

scrollViewWillScrollToTop:

Rayfleck
  • 12,116
  • 8
  • 48
  • 74
  • 1
    Thanks for the reply. Unfortunately, none of the above has worked. Strangely, the normal behaviour is observed in some tables throughout the app but not others. No scroll views are embedded in the tables anywhere. – imnk Sep 24 '10 at 10:54
0

As @imnk suggested, my thoughts as an answer, even though I don't have a real solution.

What I'm experiencing (and just verified to be sure) is, that once I change the frame property of the tableView, the touch on the statusBar doesn't work anymore...

According to the Apples documentation on UIScrollViewDelegate, every scrollView's delegate (regardless of its size) can return YES on - (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView.

But I looked through three20 and changed it in my implemetations of delegates, but with no success.

denbec
  • 1,321
  • 18
  • 25
  • Check out my answer. If you're changing this property in the viewDidLoad then you may be experiencing the double table view issue. – imnk Aug 02 '11 at 10:07