如何使用自定义控件在AVPlayerViewController中管理焦点处理?

时间:2019-12-12 16:05:42

标签: tvos avplayerviewcontroller

我尝试在tvOS电影应用的AVPlayerViewController中添加一个跳过介绍按钮(例如Netflix)。我将其作为子视图添加到contentOverlayView中,当我让它出现时,我强制使用preferredFocusEnvironments为其赋予焦点。一切安好... 直到用户导航到其他地方(例如,搜索栏或视频资产信息视图)。然后,该按钮失去焦点(预期),并且再也无法通过用户交互再次聚焦。 我试图:

  • 添加一个UIFocusGuide()
  • 将我的按钮直接放在AVPlayerViewController的视图上
  • 添加自己的子视图,其中包含AVPlayerViewController视图的按钮
  • 添加自己的子视图,其中包含contentOverlayView的按钮
  • 在同一子视图上的我的按钮上方,下方,下方(针对上述每种情况)添加其他几个按钮

最后一种方法表明,其他任何按钮都无法通过用户交互获得焦点,因此,出于相同的原因,似乎跳过-介绍按钮不能由用户聚焦。但是这是什么原因呢? 将自定义交互元素添加到AVPlayerViewController的正确做法是什么? 任何想法吗?

1 个答案:

答案 0 :(得分:0)

尝试回答我的主要问题“向 AVPlayerViewController 添加自定义交互元素的正确做法是什么?”我自己:

自从我在 1.5 年前发布这个问题以来,我并没有对跳过介绍功能的实现进行太多更改。因此,每当用户使用遥控器时,按钮都会失去焦点,我唯一改变的是,每当发生这种情况时,我都会隐藏按钮,方法是实现 didUpdateFocus(in:with:),类似于:

if let previouslyFocusedView = context.previouslyFocusedView {
    if previouslyFocusedView == skipIntroButton {
        changeSkipIntroButtonVisibility(to: 0.0)//animates alpha value
    }
}

(我不完全确定,为什么我不将其设置为 isHidden = true

然而,与此同时,我不得不为我们的播放器实现一个更复杂的叠加层,即“开始下一个视频/观看积分”的东西,带有预告片、一些按钮、倒计时/进度条等等。对于上述问题,很明显,我无法采用 contentOverlayView 方法。 所以我决定以“传统方式”实现它,在玩家的视图之上呈现一个完整的 UIViewController,如下所示:

func showNextVideoOverlay() {
    guard let nextVideoTeaser = nextVideoTeaser else { return }
    let nextVideoOverlay = NextVideoAnnouncementViewController(withTeaser: nextVideoTeaser, player: player)
    nextVideoOverlay.nextVideoAnnouncementDelegate = self
    nextVideoOverlay.modalPresentationStyle = .overFullScreen
    present(nextVideoOverlay, animated: true, completion: nil)
}

当然,NextVideoAnnouncementViewController 是透明的,因此仍然可以观看视频。事实证明,这种直截了当的方法效果很好,但我真的不知道,为什么我在实现跳过介绍时没有考虑过。

我的 QA 同事发现了一件棘手的事情,您应该意识到(我认为,我记得,这对于不同的设备和不同的遥控器以及不同的 tvOS 版本来说是不同的 - 试试看):

覆盖的视图控制器阻止了来自遥控器的大部分命令,分别地,您可以在视图控制器内部导航而不影响播放器 - 除了播放/暂停按钮。那个会暂停播放器,但不可能从那里恢复。这是因为正在播放 (av) 的播放器总是会收听此按钮,而暂停 则不会。所以我也必须实现这样的东西:

func addRemoteButtonRecognizer() {
    let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(playPauseButtonPressed))
    tapRecognizer.allowedPressTypes = [NSNumber(value: UIPress.PressType.playPause.rawValue)]
        self.view.addGestureRecognizer(tapRecognizer)
}

@objc func playPauseButtonPressed(sender: AnyObject) {
    nextVideoAnnouncementDelegate?.remotePlayButtonPressed()
}

func remotePlayButtonPressed() {
    if player?.playerStatus == .paused {
        player?.play()
    } else {
        player?.pause()
    }
}

我希望这对你们中的一些人有所帮助,他们来到这里并没有找到其他答案。