【问题标题】:tvOS UITabBarController start unfocusedtvOS UITabBarController 启动不集中
【发布时间】:2015-10-18 13:24:01
【问题描述】:

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

我曾尝试使用self.tabBarController.tabBar.userInteractionEnabled 暂时移除焦点,但徒劳无功。 (此外我不喜欢这种解决方法)

有什么线索吗?

提前致谢。

【问题讨论】:

    标签: focus uitabbarcontroller uitabbar tvos


    【解决方案1】:

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

    如果您使用故事板进行初始 UI 设置,请不要忘记将自定义类 TVTabBarController 设置为您的标签栏控制器。


    原解决方案:

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

    所以我找到了一个更好的解决方案:在第一次调用时在 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];
        }
    }
    

    【讨论】:

      【解决方案2】:

      上述方法大多有效,但不允许您通过单击选择选项卡栏项目,因为在这种情况下它应该返回 selectedItem 时返回 tabBar。这是一个改进的版本,它通过在正常情况下返回 [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];
          }
      }
      

      【讨论】:

      • 您提到闪烁很奇怪,因为使用此解决方案,标签栏永远不会获得焦点,因此永远不会显示。此外,在模拟器和电视上都没有闪烁。但是调用 super 是更好的解决方案,我将编辑我的答案。
      • 奇怪... beta3 有闪烁(beta2 不可见)所以感谢您的回答。
      • 是的,我不知道闪烁是错误还是什么。我确实注意到,即使有 1 秒的延迟,我确实看到它闪烁了一次,所以我将它延长到 2 秒。但希望通用汽车不需要这样做。
      • 谢谢,我会延长到 2 秒。
      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

        • 起初,这似乎可行,但后来我意识到,简单地隐藏标签栏不会将焦点移动到标签栏项目的视图。
        【解决方案5】:

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

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

        【讨论】:

          【解决方案6】:

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

          Swift 4.0

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

          【讨论】:

            猜你喜欢
            • 2019-04-29
            • 2020-06-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多