tvOS UITabBarController 开始不专心

tvOS UITabBarController start unfocused

我有一个以 UITabBarController 开头的简单 tvOS 应用程序,我希望主视图在应用程序启动时获得焦点,而不是标签栏。

我试过使用 self.tabBarController.tabBar.userInteractionEnabled 暂时移除焦点,但没有成功。 (此外,我不喜欢那种解决方法)

有线索吗?

提前致谢。

我找到了解决方案,所以如果有人感兴趣,您只需继承 UITabBarController 并覆盖 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

上述方法大部分都有效,但不允许您 select 标签栏项目点击 return tabBar 在这种情况下应该 return selectedItem.这是一个改进的版本,它通过 returning [super preferredViewController] 而不是正常情况下的 tabBar 来解决这个问题。这个版本还在启动时用 alpha 隐藏了标签栏,这样它就不会闪烁。可能有更优雅的方法来隐藏。

@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];
    }
}

我原来的解决方案不再适用于 tvOS 9.3,所以我找到了一个带有 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
}

如果您使用 Storyboard 进行初始 UI 设置,请不要忘记为您的标签栏控制器设置自定义 class TVTabBarController


原解:

UITabBarController 继承的建议方法对我不起作用,因为实际上 -preferredFocusedView 在启动时被调用了两次,所以我不得不向 return 添加一个计数器 self.selectedViewController.preferredFocusedView 用于前 2 个调用。但这是一个非常 hacky 的解决方案,不能保证它将来不会崩溃。

所以我找到了一个更好的解决方案:在第一次调用时在 appdelegate 的 -applicationDidBecomeActive: 中强制更新焦点。

- (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];
    }
}

这是我认为最简单、最干净的解决方案:

override var preferredFocusedView: UIView? {
        if tabBar.hidden {
            return selectedViewController?.preferredFocusedView
        }
        return super.preferredFocusedView
    }

我可以通过 UITabBarisHidden 属性 非常简单地实现这种效果。

override func viewDidLoad() {
    super.viewDidLoad()
    self.tabBar.isHidden = true
}    

当用户向上滚动以显示标签栏时,UITabBarController 会自动取消隐藏。

由于 preferredFocusedView 在 tvOS 中已弃用,您应该改写 preferredFocusEnvironments 属性

Swift 4.0

override var preferredFocusEnvironments: [UIFocusEnvironment] {
        if firsTime, let enviroments = selectedViewController?.preferredFocusEnvironments {
            firsTime = false
            return enviroments
        }
        return super.preferredFocusEnvironments
    }