Si vous définissez AVPlayerViewController.showsPlaybackControls sur false, les contrôles ne s'afficheront pas du tout. Même si vous appuyez sur l'écran.
Je veux que les commandes commencent cachées, mais je puisse toujours les invoquer en appuyant sur. Si je mets la propriété mentionnée à true, ils commencent visibles. (Oui, ils s'estompent après quelques secondes.) Existe-t-il un moyen de commencer caché, mais toujours accessible?
MISE À JOUR: J'ai fini par faire mes propres contrôles pour une meilleure personnalisation. C'est plus difficile mais ça vaut le coup. Veuillez lire l'exemple de code d'Apple pour référence. Il s'agit d'implémenter PiP mais aussi de faire des contrôles personnalisés: https://developer.Apple.com/library/prerelease/ios/samplecode/AVFoundationPiPPlayer/Introduction/Intro.html
MISE À JOUR: Lorsque vous appuyez dessus, AVPlayerViewController ne déclenche que l'événement touchesBegan, et non l'événement touchEnded. Mais il suffit de montrer les commandes.
Vous devez d'abord masquer le contrôle. Mettez ce code juste avant de présenter AVPlayerViewController
YourAVPlayerViewController.showsPlaybackControls = false
Ensuite, sous-classe AVPlayerViewController et ajoutez cette fonction:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.showsPlaybackControls = true
super.touchesBegan(touches, withEvent: event)
}
ANCIENNE SOLLUTION:
Je viens de résoudre ça. L'idée principale est de mettre une UIView au-dessus de l'AVPlayerViewController pour réactiver le geste de tapotement et de masquer cette UIView lorsqu'elle n'est plus nécessaire.
Voici le code:
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
}
}
Et lorsque vous devez masquer les contrôles, procédez comme suit:
var AVViewController = CustomAVPlayerViewController()
...
// Hide controls
AVViewController.showsPlaybackControls = false
// Show topView
AVViewController.topView.hidden = false
Je pense que j'ai résolu cela en utilisant des relations de reconnaissance de gestes dynamiques. La solution évite les contrôles personnalisés (pour la cohérence), utilise uniquement l'API publique et ne sous-classe pas AVPlayerViewController
(ce qui est explicitement interdit, comme indiqué dans d'autres réponses).
Voici comment:
Créez un contrôleur de vue de conteneur qui incorpore AVPlayerViewController
. (Ceci est utile quels que soient les contrôles, car vous devez placer la logique de lecture quelque part.)
Définissez showsPlaybackControls
sur false
initialement.
Ajoutez un UITapGestureRecognizer pour reconnaître le tap initial.
Dans la méthode d'action pour la reconnaissance de mouvement, définissez showsPlaybackControls
sur true
.
Jusqu'à présent, cela fonctionnerait, mais les commandes disparaîtraient immédiatement lors de ce tap initial. Pour résoudre ce problème, définissez-vous en tant que délégué pour la reconnaissance des gestes, implémentez gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer:
et renvoyez true
pour tout autre outil de reconnaissance gestuelle à simple pression.
Voici l'implémentation réelle dans Swift; vérifier andreyvit/ModalMoviePlayerViewController repo pour le dernier code:
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's 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
}
}
la réponse de thegathering est bonne. Je remplacerais plutôt touchesCancelled à la place pour que les contrôles ne s'affichent pas, puis se cachent à nouveau.
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
}
}
Un moyen simple de le faire dans Swift 3 est de définir myController.showsPlaybackControls = false
, et pour superposer la vue entière du lecteur avec un bouton ou un lecteur de gestes. Je l'ai intégré dans une autre vue dans un autre contrôleur sur un storyboard pour rendre cela simple et pour ne pas remplacer le contrôleur du joueur. L'astuce consiste alors à masquer le bouton après avoir été cliqué une fois, car le contrôleur du lecteur suivra ensuite les taps pour afficher/masquer les commandes.
@IBAction func enableControls(button:UIButton)
{
controller?.showsPlaybackControls = true
button.isHidden = true //The button is only needed once, then the player takes over.
}