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)
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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With