Как отключить AVPlayer в Swift, когда вы уходите из поля зрения - PullRequest
0 голосов
/ 01 августа 2020

У меня есть вид навигации из списка URL-адресов видео к месту назначения Videoview, а затем к видеоплееру. Плеер использует только AVPlayer (мне не нужны элементы управления) для автоматического воспроизведения видео, когда я перехожу к нему.

Однако видео не перестает воспроизводиться, когда я нажимаю кнопку «назад» и уйти от PlayerView.

Приветствуются любые мысли о том, как это исправить.

Я включил код из представления навигации, перехода через VideoView и PlayerView в качестве контекста . TIA.

Вид навигации

NavigationView {
            List(messages, id: \.self) { message in
                NavigationLink(destination: VideoView(videoURL: URL(string:"https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4")!,  previewLength: 15)) {
                    Text(message)
                }
            }.navigationBarTitle("Answers")

Код VideoView

struct VideoView: UIViewRepresentable {
    var videoURL:URL
    var previewLength:Double?
    
    func makeUIView(context: Context) -> UIView {
        print("making VideoView")
        return PlayerView(frame: .zero, url: videoURL, previewLength: previewLength ?? 30)
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {
        
    }

Фрагмент проигрывателя

class PlayerView: UIView {
    private let playerLayer = AVPlayerLayer()
    private var previewTimer:Timer?
    var previewLength:Double
    
    init(frame: CGRect, url: URL, previewLength:Double) {
        self.previewLength = previewLength
        super.init(frame: frame)
        
        // Create the video player using the URL passed in.
        let player = AVPlayer(url: url)
        player.volume = 2 // Will play audio if you don't set to zero

// This is the AVPlayer approach to playing video with no controls
        player.play() // Set to play once created.

        // Add the player to our Player Layer
        playerLayer.player = player
        playerLayer.videoGravity = .resizeAspectFill // Resizes content to fill whole video layer.
        playerLayer.backgroundColor = UIColor.black.cgColor

        previewTimer = Timer.scheduledTimer(withTimeInterval: previewLength, repeats: false, block: { (timer) in
            player.seek(to: CMTime(seconds: 0, preferredTimescale: CMTimeScale(1)))
        })

        layer.addSublayer(playerLayer)

1 Ответ

1 голос
/ 01 августа 2020

Вот возможный подход - использовать режим презентации при обновлении, потому что в этом сценарии он обновляется из-за перехода назад.

struct VideoView: UIViewRepresentable {
    @Environment(\.presentationMode) var presentation     // << here !!

    var videoURL:URL
    var previewLength:Double?
    
    func makeUIView(context: Context) -> UIView {
        print("making VideoView")
        return PlayerView(frame: .zero, url: videoURL, previewLength: previewLength ?? 30)
    }
    
    func updateUIView(_ playerView: PlayerView, context: Context) {
        // update might be called several times, so PlayerView should
        // be safe for repeated calls
        if presentation.wrappedValue.isPresented {
           playerView.play()
        } else {
           playerView.stop()
        }           
    }
}

и PlayerView должны быть обновлены, чтобы иметь доступ к плееру

class PlayerView: UIView {
    private let playerLayer = AVPlayerLayer()
    private var previewTimer:Timer?
    var previewLength:Double
    
    private var player: AVPlayer     // << make property

    init(frame: CGRect, url: URL, previewLength:Double) {
        self.previewLength = previewLength
        super.init(frame: frame)
        
        // Create the video player using the URL passed in.
        player = AVPlayer(url: url)
        player.volume = 2 // Will play audio if you don't set to zero

        // don't run .play() here !!!

        // ... other code
    }

    func play() {
       player.rate = 1.0
    }

    func stop() {
       player.rate = 0.0
    }
}
...