tvOS how to check if the UITabBar is focused

1.3k Views Asked by At

I'm looking for a way to make a custom transition when changing the focus from or to the UITabBar.

I'm currently trying this by overriding the didUpdateFocus method but I seem to be unable to check if the the tabBar is focused.

The tabBar itself seem to never be in the "focused" state:

override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinatora)
{
    super.didUpdateFocus(in: context, with: coordinator)

    print(self.tabBar.isFocused) // always false
}

When checking the UIFocusUpdateContext the currently focused element is a UITabBarButton.

But I'm unable to check if the context is an instance of UITabBarButton because that type isn't available:

context.nextFocusedItem is UITabBarButton // can't compile

I'm really stuck here and would love any suggestions on how to tackle this one.

Thanks.

3

There are 3 best solutions below

0
On

First add extension for UIView if it has superview:

public func hasSuperView(_ view: UIView) -> Bool {
    if self == view {
        return true
    }
    if let superview = superview {
        return superview.hasSuperView(view)
    }
    return false
}

Then add extension for UIFocusUpdateContext to check if view has focus:

public func viewHasFocus(_ view: UIView) -> Bool {
    guard let nextFocusedView = nextFocusedView else { return false }
    return nextFocusedView.hasSuperView(view) || view.hasSuperView(nextFocusedView)
}

Then use context in this method to check if tabbar has focus:

   override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
    if context.viewHasFocus(tabBar) {}
}

Also please override this method in your UITabBarController subclass

0
On

This answer probably won't help the OP (it was asked more than a year ago), but as I was struggling with the same issue, a presentation from WWDC17 helped me figure it out:

UIView, UIViewController, UIWindow, etc. all conform to the UIFocusEnvironment protocol. The tabBar itself never actually receives direct focus, so the correct way to check if one of its buttons has focus is by checking if its environment contains the UIFocusItem:

override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
    if let nextFocusedItem = context.nextFocusedItem,
        self.tabBar.contains(nextFocusedItem) {
        //Do some stuff
    }
}

I'm sure the asker figured this out ages ago, but I thought I'd throw this answer up for anyone else that happens to have the same question later.

0
On

I have created extension on UIView which will check if there is focus somewhere in its hierarchy:

func containsFocus() -> Bool {
    if self.isFocused { return true }
    else {
        for subview in self.subviews {
            if subview.containsFocus() { return true }
        }

        return false
    }
}

This way you can check if your UITabBar has focus.

Note:

This is very expensive way of checking if your view has focus, because it is recursive function and it will potentially traverse the whole hierarchy of your view.

Tip:

If you are trying to implement custom transition when selecting tabs in UITabBar you should use UITabBarDelegate method:

 func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem)

If not, just ignore this tip.