ios video avplayer

ios - avplayer swift 4



Ocultar controles en AVPlayerViewController: solo al inicio (4)

Si configura AVPlayerViewController.showsPlaybackControls en falso, los controles no se mostrarán en absoluto. Incluso si toca la pantalla.

Quiero que los controles comiencen ocultos, pero aún así poder invocarlos tocando. Si configuro la propiedad mencionada como verdadera, comienzan a ser visibles. (Sí, se desvanecen después de unos segundos). ¿Hay alguna forma de comenzar oculto, pero aún así ser accesible?


ACTUALIZACIÓN: terminé haciendo mis propios controles para una mejor personalización. Es más difícil pero vale la pena el tiempo. Por favor, lea el código de muestra de Apple para referencia. Se trata de implementar PiP, pero también de hacer controles personalizados: https://developer.apple.com/library/prerelease/ios/samplecode/AVFoundationPiPPlayer/Introduction/Intro.html

ACTUALIZACIÓN: cuando se toca, AVPlayerViewController solo activa el evento touchesBegan y no el evento touchesEnded. Pero es suficiente para mostrar los controles.

Primero necesitas ocultar el control. Coloque este código justo antes de presentar AVPlayerViewController

YourAVPlayerViewController.showsPlaybackControls = false

Luego, subclase AVPlayerViewController y agregue esta función:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { self.showsPlaybackControls = true super.touchesBegan(touches, withEvent: event) }

SOLUCIÓN VIEJA:

Acabo de resolver esto. La idea principal es colocar una UIView encima de AVPlayerViewController para reverenciar el gesto de toque y ocultar esa UIView cuando ya no sea necesaria.

Aquí está el código:

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 } }

Y cuando necesite ocultar los controles, haga esto:

var AVViewController = CustomAVPlayerViewController() ... // Hide controls AVViewController.showsPlaybackControls = false // Show topView AVViewController.topView.hidden = false


Creo que he resuelto esto usando relaciones dinámicas de reconocimiento de gestos. La solución evita controles personalizados (por coherencia), usa solo API pública y no subclase AVPlayerViewController (que está explícitamente prohibido, como se indica en otras respuestas).

Así es cómo:

  1. Cree un controlador de vista de contenedor que incorpore AVPlayerViewController . (Esto es útil independientemente de los controles, porque necesita colocar la lógica de reproducción en alguna parte).

  2. Establecer showsPlaybackControls en false inicialmente.

  3. Agregue un UITAPGestureRecognizer para reconocer el toque inicial.

  4. En el método de acción para el reconocedor de gestos, establezca showsPlaybackControls en true .

  5. Hasta ahora, funcionaría, pero los controles desaparecerían inmediatamente en ese toque inicial. Para solucionarlo, gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer: como un delegado para el reconocedor de gestos, implemente gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer: y devuelva true para cualquier otro reconocedor de gestos de un solo toque.

Aquí está la implementación real en Swift; revise el andreyvit/ModalMoviePlayerViewController para el último código:

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 } }


Una forma simple de hacerlo en Swift 3 es establecer myController.showsPlaybackControls = false , y superponer toda la vista del jugador con un botón o un reconocedor de gestos. Lo incrusto en otra vista en otro controlador en un guión gráfico para hacerlo simple y no anular el controlador del reproductor. El truco consiste entonces en ocultar el botón después de hacer clic una vez, ya que el controlador del reproductor seguirá los toques para mostrar / ocultar los controles.

@IBAction func enableControls(button:UIButton) { controller?.showsPlaybackControls = true button.isHidden = true //The button is only needed once, then the player takes over. }


la respuesta de thegathering es buena. Anularía toques cancelados en su lugar para que los controles no se muestren y luego se oculten de nuevo.

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 } }