2

So I have a viewController with a tableView that is being presented from a tabBarController. If the user taps the tabBarItem for the view that is already being shown, I want the tableView to scroll to the top. I have set the UITabBarControllerDelegate to be the viewController and then added the following method:

func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
    if tabBarController.selectedIndex == 0 {
        //scroll to the top!
    }
}

The problem is that the tableView scrolls to the top regardless of the current view. So I tried to add a second condition that makes sure that the currently displayed view is the correct one but nothing seemed to be correct.

TL;DR

How can I tell that the user is tapping on the tabBarItem that is already selected?

Matt Bart
  • 809
  • 1
  • 7
  • 26
  • Have you written `override` in front of `func tabBarController(...)`? – Alexandre Fenyo Aug 03 '18 at 22:17
  • @AlexandreFenyo nope, I don't think it needs to have that. I can confirm that the function is being called, I'm having the problem of what should go inside the function – Matt Bart Aug 03 '18 at 23:53

1 Answers1

3

You can use self.view.window != nil to determine if the view of the vc is already displayed. Use shouldSelect delegate method, which is called before the selection.

func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {



    if viewController === self && self.isViewLoaded {

    // Please use viewController === self.navigationController
    // if self is a child of a UINavigationController. We should
    // compare the viewController with a direct child of the 
    // UITabController

        if self.view.window != nil {
            print("scroll to top")
        } else {
            print("Don't scroll to top")
        }
    }
    return true
}
ukim
  • 2,395
  • 15
  • 22
  • I like the idea of using shouldSelect rather than didSelect, but there is still logic errors here. When adding these two lines of codes: `print(self.isViewLoaded) print(viewController === self)` I reveal that it always prints `true` and `false` – Matt Bart Aug 03 '18 at 23:58
  • For some reason `viewController === self` (or something like `viewController == self`) always returns `false` – Matt Bart Aug 04 '18 at 00:00
  • 1
    I guess your vc has a navigation controller. In this case you should use (viewController === self.navigationController). We want to compare the direct child of the tab bar controller. And you should use ===, because you want to make sure there two pointers refer to the same view controller. – ukim Aug 04 '18 at 00:08
  • @MattBart sorry I forgot to @ you – ukim Aug 04 '18 at 00:09
  • Awesome that is the bug that I have been looking for! One thing about your answer though is that I had to add `tabBarController.selectedIndex == 0` because the views are being controlled by the tabBarController they are still loaded even if you are looking at a different tab, thus `self.isViewLoaded` is always true. So my statement looks like this: `if viewController === self.navigationController && tabBarController.selectedIndex == 0 {` The if statement that you have is `true` even if a user selects the tab from another tab. – Matt Bart Aug 04 '18 at 00:30
  • Will accept the answer when you correct the answer ;) – Matt Bart Aug 04 '18 at 00:32