didSelectViewController not getting called when in "More" section
Asked Answered
L

2

10

I have a UITabBarController and I have set up its delegate method didSelectViewController, as I am interested in the index of the tab that is being selected.

However, I noticed that the didSelectViewController method doesn't get called when the user is in the "More" section (when there are more tabs than can be shown in the tabbar):

The problematic section

Is there a way for me to get notified of the items the user selects from the table that is being automatically created?

Lattimer answered 27/4, 2011 at 11:31 Comment(1)
I've tried to figure this one out too. I can get as far as knowing when they tap More, but to see which view controller they select from More's tableviewcontroller requires using non-public api calls.Chongchoo
L
9

I found what I needed in this question.

Basically you set up a UITabBarControllerDelegate and a UINavigationControllerDelegate for the navigation controller that is displayed inside the More tab. After that you detect if the user touched one of the visible tabs, or the "More" tab.

EDIT

Also, to directly manipulate the table that is visible within the "More" navigation controller, you can set up a "man-in-the-middle" table view delegate, that intercepts the calls to the original delegate. See code from inside didSelectViewController below:

if (viewController == tabBarController.moreNavigationController && tabBarController.moreNavigationController.delegate == nil) {
    // here we replace the "More" tab table delegate with our own implementation
    // this allows us to replace viewControllers seamlessly

    UITableView *view = (UITableView *)self.tabBarController.moreNavigationController.topViewController.view;
    self.originalDelegate = view.delegate;
    view.delegate = self;
}

After that, you are free to do whatever you like inside the delegate methods, as long as you call the same methods in the other delegate (I actually checked to which methods the original delegate responds, and the only delegate method that is implemented is the didSelectRow:forIndexPath:). See an example below:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // this is the delegate for the "More" tab table
    // it intercepts any touches and replaces the selected view controller if needed
    // then, it calls the original delegate to preserve the behavior of the "More" tab

    // do whatever here 
    // and call the original delegate afterwards
    [self.originalDelegate tableView: tableView didSelectRowAtIndexPath: indexPath];
}
Lattimer answered 27/4, 2011 at 14:9 Comment(1)
Have you tried NSLog both delegate to see if it different ? Look like it's the same.Epizootic
G
1

Previous answer is almost correct because it misses one method to work properly.

class MyClass: ... {

    var originalTableDelegate: UITableViewDelegate?
}

extension MyClass: UITabBarControllerDelegate {

    func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
        if viewController == tabBarController.moreNavigationController && originalTableDelegate == nil {
            if let moreTableView = tabBarController.moreNavigationController.topViewController?.view as? UITableView {
                originalTableDelegate = moreTableView.delegate
                moreTableView.delegate = self
            }
        }
    }
}

extension MyClass: UITableViewDelegate {
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        originalTableDelegate!.tableView!(tableView, willDisplay: cell, forRowAt: indexPath)
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("intercepted")
        originalTableDelegate?.tableView!(tableView, didSelectRowAt: indexPath)
    }
}

The original table delegate on more controller is actually system hidden class UIMoreListController. If we take a look into its implementation we will notice these two overrided functions: didSelect and willDisplay.

NOTE:

There could be a potential problem with this delegate interception if Apple decide to implement some other delegate method in its own UIMoreListController in future iOS versions.

Gaussmeter answered 5/9, 2018 at 9:37 Comment(1)
Uhm, I have completely forgotten what this was about, since it was almost 7 years ago...Lattimer

© 2022 - 2024 — McMap. All rights reserved.