TableViewController doesn't flash scroll indicators even if the table is bigger that the view
Asked Answered
G

5

16

I've got a weird problem with a TableViewController. In the doc it says that a tableViewController deals also with the method -flashScrollIndicators when the table is "oversized" respect the visible area.

My app consists in 3 nav controller loaded in a tab controller. Each nav controller has as root view controller a subclass of a table view controller. Each "model" is populated from a plist file, that loads its contents into an array in the -viewDIdLoad, later everything is passed to the table. Everything is loaded programmatically no IB.

I've found out in my app that when it loads the first view (a nav controller with a table view controller as root) the scroll bar isn't flashing even if the number of cell it's great enough. If I choose another tab, that loads another nav controller (with a t.v.c. as root) scroll bar isn't shown again. When I press the tab corresponding to the first nav controller loaded the scrollbar flashes.

So I've tried to make it flash programmatically but no way, the code seems simple:

[self.tableView flashScrollIndicators];

I've tried to put it almost everywhere. First in the -viewDidLoad (As suggested in the doc), then in viewDidAppear and in -viewWillAppear. Also tried use that code tring to cast the view of the t.v.c. as a table view.

[((UITableView*)self.view) flashScrollIndicators];

..without result.

I've started looking at Apple sample and I've found that in Apple's table view custom sample (the one with different times) scroll bar doesn't flash also there. Tested both on sim and device.

Is a bug?, is there a correct way to show it programmatically? Can someone help me? Regards, Andrea

Garvey answered 19/7, 2010 at 14:21 Comment(4)
It should just work when you call flashScrollIndicators, but I can confirm it can be extremely frustrating to pinpoint the best place to put things like this. There's no penalty in calling it twice btw so just litter your project with this call ;-)Catherincatherina
Hi mvds unfortunately it doesn't work even if I try to call by myself in -viewDidLoad , -viewWillAppear, -viewDidAppear.Garvey
Did you check that self.tableView is not nil? Did you try a -reloadData first?Balzer
Well, Ortwin...THANKS. Of course the Table wasn't nil. Using reloadData everything works. Could you write as an answer? so we could solve it.Garvey
T
41

Or more concisely:

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];
  [self.tableView performSelector:@selector(flashScrollIndicators) withObject:nil afterDelay:0];
}
Tade answered 9/12, 2010 at 13:33 Comment(6)
This works!!! Thanks! I use this in acaniChat to flash the scroll indicators of the UITableView *chatContent when the UIViewController *chatViewController appears.Marco
edited, forgetting to call implementation of the super class is the bad habit ;)Lollop
I was using just [self.scrollView flashScrollIndicators]; which did not work in a particular case, whereas your performSelector solution does work great. Thanks.Defensible
I was having this same issue, I tried the delayed performSelector and noticed something very interesting. My tableView is presented in a UIPopover that is invoked by a user tap. If I hold my finger down after the tap that brings up the popover, the scroll indicators never flash. If I release quick enough (before my delayed performSelector), the indicators flash. So there is something going on to prevent them from flashing if the user keeps holding their finger down while the tableView is being cranked up.Bothersome
Wow, it really works!!, But for me I am using UIPageViewController where in the UIViewController has a scrollview flashing the scroll indicator doesnt works, I tried using it inside viewWillAppear and viewDidAppear. Thanks for this awesome fix. But Im curious what is the reason behind this.Granule
its also working without perform selector in viewDidAppear method. [self. tableView flashScrollIndicators];Canyon
S
12

I had exactly the same problem. I got around it in the end by putting a delayed selector in the viewDidAppear: method. Weirdly, I can set it to 0 seconds and it still works fine.

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    [self performSelector:@selector(flashTableScrollIndicators) withObject:nil afterDelay:0.0];
}

- (void)flashTableScrollIndicators
{
    [self.tableView flashScrollIndicators];
}
Sherillsherilyn answered 18/8, 2010 at 17:4 Comment(2)
That's the solution I was looking for.THX. Regards, AndreaGarvey
you can also do it like this [self.tableView performSelector:@selector(flashScrollIndicators) withObject:nil afterDelay:0.0];Lollop
C
3

It is not displayed when you show section index titles.

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView; 
Comeback answered 7/5, 2013 at 14:50 Comment(0)
L
0

My solution was to send the "flashScrollIndicators()" message with a slight delay using "dispatch_after":

let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(0.4 * Double(NSEC_PER_SEC)))

dispatch_after(delayTime, dispatch_get_main_queue(), 
{ () -> Void in 
    myScrollView.flashScrollIndicators() 
})
Lifeboat answered 30/12, 2014 at 2:43 Comment(0)
H
0

The likely cause is that the UITableView has not yet laid out its subviews when you are calling .flashScrollIndicators(), so no flashing occurs, there is no content to scroll. This is correct and expected behaviour.

Simply call .layoutIfNeeded() on the UITableView before you call .flashScrollIndicators().

TLDR Solution:

func reloadMyTableViewFlashingIndicators() {
    // assuming you have set your DataSource to load into the TableView
    // e.g. yourTableViewDataSource = tableData

    // Reload the rows and sections of the table view.
    yourTableViewController.reloadData()

    // now, lay out the subviews immediately, if layout updates are pending.
    // which they are due to calling .reloadData()
    // this instructs - Do not wait for the next layout update cycle.
    yourTableViewController.layoutIfNeeded()

    // Now it is known how much content the TableView's ScrollView has and will
    // flash the indicators when there is content to scroll.
    yourTableViewController.flashScrollIndicators()
}

Tips:

Remember, initially the TableViewController is empty so there is no content in the TableView's ScrollView, i.e. no flashing of Scroll Indicators.

This is especially true when you are calling .reloadData() or .flashScrollIndicators() from within a ViewController's lifecycle functions, viewDidAppear or viewWillAppear. When those functions are performed, the ViewController has completed laying out an initially empty TableView, i.e. no content, no flashing scroll indicators.

Even if you have content in your TableView's DataSource when you call .reloadData() followed by .flashScrollIndicators(), the scope you call that in does not wait for subviews to layout (nor should it).

for example:

func willNotFlashIndicators() {
    // assuming you have set your DataSource to load into the TableView
    // e.g. yourTableViewDataSource = tableData

    // Reload the rows and sections of the table view.
    yourTableViewController.reloadData()

    // iOS has not yet laid out the TableView's content.
    // layout updates are queued and will occur during the next layout engine update.
    // At this point the TableView's ScrollView's content layout is still empty,
    // i.e. no flashing of Scroll Indicators.
    // This is correct and expected behaviour.
    yourTableViewController.flashScrollIndicators()
}

Swift does not assume you always want to layout subviews immediately when you call .reloadData(), which is a good thing, as it provides more default control to the developer for one. Mastering when you want the layout engine to perform updates on certain Views and it's subviews immediately is key.

Happy developing!

Hardigg answered 29/7 at 1:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.