Scroll to top of UITableView by tapping status bar
Asked Answered
C

9

60

I know there's tons of code out there to scroll a tableview to the top, but I want to do this when the top status bar is tapped, just like in Apple's native apps. Is this possible?

Calcific answered 23/8, 2011 at 18:38 Comment(1)
I tested (iOS 8) and found that item "3" from Zane Claes checklist is not necessary.Thagard
B
154

You get this for free, but you should check that the scrollsToTop attribute of your UITableView is YES.

When this does NOT work is when you have a UIScrollView (or descendant class like UITextView) object embedded inside another UIScrollView class (like UITableView). In this case, set scrollsToTop on the embedded UIScrollView class to NO. Then the tap-the-status-bar behavior will work.

Barby answered 23/8, 2011 at 18:41 Comment(11)
I've tried what you suggest – setting the embedded scrollview's scrollsToTop to NO – but the status bar tap still doesn't cause the top scrollview to scroll to the top.Amoreta
This works perfectly. @Amoreta perhaps you have more than one embedded scroll view onscreen. They must all be set to NO apart from the scroll view at the top of the view hierarchy.Virelay
In my case I had some horizontally scrolling collection views within my vertically scrolling table view, setting scrollsToTop to NO for all of the collection views worked. Seems unintuitive but it worked!Goeselt
@Amoreta note that scrollsToTop = NO rule must be applied to all views within a window. For example, in case when you have side menu.Berget
Thank you! This helped me also. Setting scrollsToTop = YES to my tableview and to my customTableViewCell's TextView, I set it to NO.Navigator
This was occurring in my UICollectionView. I had a side-scrolling UIScrollView within each UICollectionViewCell. Setting scrollsToTop = NO to the cell's scrollView fixed the issue. ThanksCoolish
How does one figure this out, thnx!Albumose
This has stopped working for iOS9. Can you give me a hack for this.Mushroom
Oh, I think not, @FaisalShaikh. I suggest reading the documentation for scrollsToTop carefully. Make sure only the scroll view (or descendent) class you want to scroll to top when the status bar is tapped has scrollsToTop set to YES. Any other scroll views embedded in your main scroll view should have scrollsToTop set to NO. If more than one scroll view has scrollsToTop set to YES, then the gesture is ignored.Barby
In my screen, status bar is hidden. Is there any workaround to achieve this?Metaphor
@Metaphor I think you would have to implement your own tap gesture recognizer in the view that is visible to detect a touch at the top of the screen and then in code cause your content to scroll to the top.Barby
E
31

If you came from Google and need a complete checklist:

  1. Check that you've set scrollsToTop=YES (per Mark's suggestion) on your UITableView
  2. Make sure that you've set scrollsToTop=NO on all OTHER UITableViews / UIScrollViews / UITextViews in your window, so that they're not intercepting the click. I've found myself printing out all the views in my window many times to debug this...
  3. Make sure that your table view is at 0/0 (x/y coordinates) within the window - this is how the system knows that it should pass the message
Epicrisis answered 10/4, 2013 at 15:36 Comment(4)
What if it's in a child view controller that puts it below 0,0 within the window?Wallack
This was useful when you use multiple uiwebviews as you need to set non active webviews' scrollstotop properties to NOVaulted
Thank you for this complete checklist. Searched my code for UITextView and found the one causing issues.Eyecatching
As @Wallack asked - @Zane/@Kyle - what if it's in a child view controller that puts it below 0,0 within the window?Prohibitive
I
6

Using the information given in other answers, I added the following code to my UITableViewController get it to work:

- (void)viewDidLoad
{
    [super viewDidLoad];

    for (UITextView *view in self.view.subviews) {
        if ([view isKindOfClass:[UITextView class]]) {
            view.scrollsToTop = NO;
        }
    }

    self.tableView.scrollsToTop = YES;
}

This looks through all the views in the UITableViewController's hierarchy and turns off scrollsToTop on all the UITextViews that were intercepting the touch event. Then, ensured the tableView was still going to receive the touch.

You can mod this to iterate through other UITableViews / UIScrollViews / UITextViews that may be intercepting as well.

Hope this helps!

Irenairene answered 7/2, 2014 at 23:10 Comment(1)
Actually you could just change UITextView to UIScrollView in your code and it would catch all UITableViews and UITextViews since they are both subclasses of UIScrollView.Bearnard
D
6

I had the same problem but fixed by following steps:

  1. Set scrollsToTop = YES for tableview you wanted to scroll to top.
  2. set scrollsToTop = NO for all other tableview or collection view or scrollview.
  3. If any of your tableview cell has collection view . Make sure you set scrollsToTop to NO for the collection view as well.

If your view controller/ navigation controller is added as a subview on another view controller, Make sure you set it as a child Controller.

Desdamonna answered 27/11, 2015 at 1:28 Comment(1)
Calling addChildViewController() was the missing piece. Thanks!Conglobate
O
3

I know this is quite an old one but hope this can help. Following what @MarkGranoff said, the scrollsToTop doesn't work if more than one UIScrollView, or its subclasses, has got it set to YES (default value), a sanity check is probably worth to check who's actually messing up with this behaviour. The simple method below loop over the subviews of your view and logs the scrollsToTop value of all the UIScrollView in your view. Preferably to be called in your viewDidAppear method.

- (void)checkForScrollViewInView:(UIView *)view {
    for (UIView *subview in [view subviews]) {
        if ([subview isKindOfClass:[UIScrollView class]]) {
            NSLog(@"scrollsToTop enabled: %i in scroll view %@", ((UIScrollView *)subview).scrollsToTop, subview);
        }
        if (subview.subviews.count > 0) {
            [self checkForScrollViewInView:subview];
        }
    }
}

This is just a debug code indeed. Once you find the scrollsToTop value for each one of the UIScrollView subclasses just make sure only one is set to YES.

Oklahoma answered 21/8, 2015 at 4:7 Comment(0)
I
2

Like Mark said, you can only have one subclass of UIScrollView (usually the table view) that has the scrollsToTop property set to TRUE. Likely you have others, typically UITextView in your view. Just set their scrollsToTop property to FALSE and you're good to go.

Intoxicant answered 2/11, 2013 at 2:55 Comment(1)
This was my issue, I had 2 table views on the same screen, each with an outlet so simply setting one to false did the trick for me, thanks!Thingumabob
N
1

On UIScrollView header file:

// When the user taps the status bar, the scroll view beneath the touch which is closest to the status bar will be scrolled to top, but only if its scrollsToTop property is YES, its delegate does not return NO from shouldScrollViewScrollToTop, and it is not already at the top. // On iPhone, we execute this gesture only if there's one on-screen scroll view with scrollsToTop == YES. If more than one is found, none will be scrolled.

Neisse answered 26/8, 2016 at 11:47 Comment(0)
L
0

For example if you have a table view and scroll view like tags like this

enter image description here

you should make something like this in viewDidLoad

self.tableView.scrollsToTop = true
self.tagsView.scrollsToTop = false
Lxx answered 3/12, 2016 at 14:18 Comment(0)
I
0

There can be multiple UIScrollView descendants loaded eg.: having a UIPageViewcontroller on each page containing UITableViews.

The scrollsToTop property is true by default.

So in addition to handling nested UIScrollViews' scrollsToTop property, you should do the following:

//When the view is loaded disable scrollsToTop, this view may not be the visible one
override func viewDidLoad() {
    super.viewDidLoad()
    ...
    tableView.scrollsToTop = false
}

//Now it's time to enable scrolling, the view is guaranteed to be visible
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    tableView.scrollsToTop = true
}

//Do not forget to disable scrollsToTop, making other visible UIScrollView descendant be able to be scrolled to top
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    self.tableView.scrollsToTop = false
}

This way only one top level UITableView's scrollsToTop will be set to true.

Installation answered 9/3, 2018 at 14:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.