Скрыть элементы управления в AVPlayerViewController - только при запуске
Если вы установите для параметра AVPlayerViewController.showsPlaybackControls значение false, элементы управления не будут отображаться вообще. Даже если вы коснетесь экрана.
Я хочу, чтобы элементы управления начали скрываться, но все же можно вызвать их, нажав. Если я установил указанное свойство в true, они начнут видны. (Да, они исчезают через несколько секунд.) Есть ли способ начать скрывать, но все же быть доступен?
Ответы
Ответ 1
UPDATE: я создал собственные элементы управления для лучшей настройки. Это сложнее, но стоит того времени. Пожалуйста, прочитайте образец кода Apple для справки. Это о внедрении PiP, а также о создании пользовательских элементов управления: https://developer.apple.com/library/prerelease/ios/samplecode/AVFoundationPiPPlayer/Introduction/Intro.html
UPDATE: при нажатии, AVPlayerViewController запускает событие touchBegan и не касается событияEnded. Но этого достаточно, чтобы показать элементы управления.
Сначала вам нужно скрыть элемент управления. Поместите этот код прямо перед тем, как представить AVPlayerViewController
YourAVPlayerViewController.showsPlaybackControls = false
Затем подкласс AVPlayerViewController и добавьте эту функцию:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.showsPlaybackControls = true
super.touchesBegan(touches, withEvent: event)
}
СТАРОЕ РАСПРОСТРАНЕНИЕ:
Я только что решил это. Основная идея состоит в том, чтобы поместить UIView поверх AVPlayerViewController, чтобы выявить жест нажатия, и скрыть этот UIView, когда он больше не нужен.
Здесь код:
import AVKit
import UIKit
// Create a custom AVPlayerViewController
@available(iOS 8.0, *)
final class CustomAVPlayerViewController: AVPlayerViewController {
// Create a UIView to put on top of all
lazy var topView = UIView(frame: CGRectMake(0, 0, width, height))
override func viewDidLoad() {
super.viewDidLoad()
// For sure, set it to clearcolor
// (DON'T set alpha = 0 because it will stop receiving user interaction)
topView.backgroundColor = UIColor.clearColor()
// Add it to the view of AVPlayerViewController
self.view.addSubview(topView)
// Bring it to front
self.view.bringSubviewToFront(topView)
// Add a tap gesture recognizer
topView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "handleTap"))
}
// Handle the tap
func handleTap() {
// Show the control
self.showsPlaybackControls = true
// Hide the topView. You can unhide it when needed later.
self.topView.hidden = true
}
}
И когда вам нужно скрыть элементы управления, сделайте следующее:
var AVViewController = CustomAVPlayerViewController()
...
// Hide controls
AVViewController.showsPlaybackControls = false
// Show topView
AVViewController.topView.hidden = false
Ответ 2
Думаю, я решил это с помощью динамических отношений распознавания жестов. Решение позволяет избежать настраиваемых элементов управления (для согласованности), использует только открытый API и не подклассы AVPlayerViewController
(который явно запрещен, как указано в других ответах).
Вот как:
-
Создайте контроллер контейнера, в который встроен AVPlayerViewController
. (Это полезно независимо от элементов управления, потому что вы должны куда-то помещать логику воспроизведения.)
-
Сначала установите showsPlaybackControls
в false
.
-
Добавьте распознаватель UITapGestureRecognizer для распознавания начального нажатия.
-
В методе действий для распознавателя жестов установите showsPlaybackControls
в true
.
-
До сих пор это сработало бы, но элементы управления сразу исчезнут при этом первоначальном нажатии. Чтобы исправить это, установите себя как делегат для распознавателя жестов, выполните gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer:
и верните true
для любого другого распознавателя жестов одного касания.
Здесь фактическая реализация в Swift; проверьте andreyvit/ModalMoviePlayerViewController repo для последнего кода:
import UIKit
import AVKit
import AVFoundation
public class ModalMoviePlayerViewController: UIViewController {
private let fileName: String
private let loop: Bool
private var item: AVPlayerItem!
private var player: AVPlayer!
internal private(set) var playerVC: AVPlayerViewController!
private var waitingToAutostart = true
public init(fileName: String, loop: Bool = true) {
self.fileName = fileName
self.loop = loop
super.init(nibName: nil, bundle: nil)
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public override func viewDidLoad() {
super.viewDidLoad()
let url = NSBundle.mainBundle().URLForResource(fileName, withExtension: nil)!
item = AVPlayerItem(URL: url)
player = AVPlayer(playerItem: item)
player.actionAtItemEnd = .None
player.addObserver(self, forKeyPath: "status", options: [], context: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ModalMoviePlayerViewController.didPlayToEndTime), name: AVPlayerItemDidPlayToEndTimeNotification, object: item)
playerVC = AVPlayerViewController()
playerVC.player = player
playerVC.videoGravity = AVLayerVideoGravityResizeAspectFill
playerVC.showsPlaybackControls = false
let playerView = playerVC.view
addChildViewController(playerVC)
view.addSubview(playerView)
playerView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
playerView.frame = view.bounds
playerVC.didMoveToParentViewController(self)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ModalMoviePlayerViewController.handleTap))
tapGesture.delegate = self
view.addGestureRecognizer(tapGesture)
}
deinit {
player.pause()
player.removeObserver(self, forKeyPath: "status")
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func togglePlayPause() {
if isPlaying {
pause()
} else {
play()
}
}
func restart() {
seekToStart()
play()
}
func play() {
if player.status == .ReadyToPlay {
player.play()
} else {
waitingToAutostart = true
}
}
func pause() {
player.pause()
waitingToAutostart = false
}
var isPlaying: Bool {
return (player.rate > 1 - 1e-6) || waitingToAutostart
}
private func performStateTransitions() {
if waitingToAutostart && player.status == .ReadyToPlay {
player.play()
}
}
public override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
performStateTransitions()
}
@objc func didPlayToEndTime() {
if isPlaying && loop {
seekToStart()
}
}
private func seekToStart() {
player.seekToTime(CMTimeMake(0, 10))
}
public override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if !playerVC.showsPlaybackControls {
playerVC.showsPlaybackControls = true
}
super.touchesBegan(touches, withEvent: event)
}
}
extension ModalMoviePlayerViewController: UIGestureRecognizerDelegate {
@IBAction func handleTap(sender: UIGestureRecognizer) {
if !playerVC.showsPlaybackControls {
playerVC.showsPlaybackControls = true
}
}
/// Prevents delivery of touch gestures to AVPlayerViewController gesture recognizer,
/// which would cause controls to hide immediately after being shown.
///
/// `-[AVPlayerViewController _handleSingleTapGesture] goes like this:
///
/// if self._showsPlaybackControlsView() {
/// _hidePlaybackControlsViewIfPossibleUntilFurtherUserInteraction()
/// } else {
/// _showPlaybackControlsViewIfNeededAndHideIfPossibleAfterDelayIfPlaying()
/// }
public func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailByGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if !playerVC.showsPlaybackControls {
// print("\nshouldBeRequiredToFailByGestureRecognizer? \(otherGestureRecognizer)")
if let tapGesture = otherGestureRecognizer as? UITapGestureRecognizer {
if tapGesture.numberOfTouchesRequired == 1 {
return true
}
}
}
return false
}
}
Ответ 3
Ответ на вопрос хорош. Вместо этого я бы отменил touchsCancelled, чтобы элементы управления не отображались, а затем снова скрывались.
override public func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
super.touchesCancelled(touches, withEvent: event)
// toggle the player controls on if they were set to off
if !self.showsPlaybackControls {
self.showsPlaybackControls = true
}
}
Ответ 4
Простым способом сделать это в Swift 3 является установка myController.showsPlaybackControls = false
и наложение всего игрового представления с помощью кнопки или распознавателя жестов. Я вставляю его в другое представление в другом контроллере на раскадровке, чтобы сделать это простым и не переопределять контроллер плеера. Трюк тогда состоит в том, чтобы скрыть кнопку после щелчка один раз, потому что после этого контроллер проигрывателя будет отслеживать ответвления, чтобы отображать/скрывать элементы управления.
@IBAction func enableControls(button:UIButton)
{
controller?.showsPlaybackControls = true
button.isHidden = true //The button is only needed once, then the player takes over.
}