I have a simple tvOS application starting with a UITabBarController
and I wish the main view to have the focus when the app launches, not the tab bar.
I've tried playing with self.tabBarController.tabBar.userInteractionEnabled
to remove temporarily the focus, but in vain. (Besides I do no like that kind of workaround)
Any clue?
Thanks in advance.
My original solution no longer works on tvOS 9.3, so I found a new one with subclassing UITabBarController
:
@interface TVTabBarController : UITabBarController
@property (nonatomic) BOOL useDefaultFocusBehavior;
@end
@implementation TVTabBarController
- (UIView *)preferredFocusedView {
return self.useDefaultFocusBehavior ? [super preferredFocusedView] : self.selectedViewController.preferredFocusedView;
}
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator {
[super didUpdateFocusInContext:context withAnimationCoordinator:coordinator];
self.useDefaultFocusBehavior = YES;
}
@end
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.tabBarController.tabBar.hidden = YES; // or do it in storyboard
}
If you use storyboard for initial UI setup, don't forget to set custom class TVTabBarController
to your tab bar controller there.
Proposed approach with inheriting from UITabBarController
didn't work for me because in fact -preferredFocusedView
is called twice on startup, so I had to add a counter to return self.selectedViewController.preferredFocusedView
for the first 2 calls. But it's a really hacky solution and there's no guarantee that it won't break in future.
So I found a much better solution: force focus update in appdelegate's -applicationDidBecomeActive:
on the first call.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.tabBarController.tabBar.hidden = YES;
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
static BOOL forceFocusToFirstTab = YES;
if (forceFocusToFirstTab) {
forceFocusToFirstTab = NO;
[self.tabBarController.selectedViewController updateFocusIfNeeded];
}
}
The above approach mostly works but does not allow you to select a tab bar item with click as it returns the tabBar in that case when it should return the selectedItem. Here is an improved version which solves this by returning [super preferredViewController] instead of tabBar in the normal case. This version also hides the tab bar with alpha at launch so that it doesn't flicker in. There are probably more elegant ways to do the hiding.
@interface MWTabBarController ()
@property (nonatomic, assign) BOOL firstTime;
@end
@implementation MWTabBarController
- (void)viewDidLoad {
[super viewDidLoad];
self.firstTime = YES;
self.tabBar.alpha = 0;
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(unAlphaTabBar) userInfo:nil repeats:NO];
}
- (void) unAlphaTabBar
{
self.tabBar.alpha = 1;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (UIView *)preferredFocusedView {
if (self.firstTime) {
self.firstTime = NO;
return self.selectedViewController.preferredFocusedView;
}
else {
return [super preferredFocusedView];
}
}
I've found the solution, so if someone is interested, you just have to subclass UITabBarController
and to override preferredFocusedView
:
@interface ZTWTabBarController ()
@property (nonatomic, assign) BOOL firstTime;
@end
@implementation ZTWTabBarController
- (void)viewDidLoad {
[super viewDidLoad];
self.firstTime = YES;
}
- (UIView *)preferredFocusedView {
if (self.firstTime) {
self.firstTime = NO;
return self.selectedViewController.preferredFocusedView;
}
else {
return [super preferredFocusedView];
}
}
@end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With