Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deactivate AVPlayer in Swift when you navigate away from view

Tags:

ios

swift

swiftui

I have a navigation view from a list of video urls to a destination Videoview and then to a video player. The player uses just the AVPlayer (I don't need controls) to automatically play the video when I navigate to it.

However the video does not stop playing when I hit the 'back' button and navigate away from the PlayerView.

Any thoughts on how to fix this are appreciated.

I've included code from the Navigation view, the pass thru VideoView and the PlayerView as context. TIA.

Navigation view

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 code

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

Player Snippet

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)

like image 325
Arsene Lupin Avatar asked Dec 31 '25 03:12

Arsene Lupin


1 Answers

Here is possible approach - to use presentation mode on update, because in this scenario it is updated due to navigation back.

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

and PlayerView should be updated to have access to player

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
    }
}
like image 53
Asperi Avatar answered Jan 01 '26 17:01

Asperi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!