ios - 离开 View 时如何在 Swift 中停用 AVPlayer

标签 ios swift swiftui

我有一个从视频 URL 列表到目标 Videoview 再到视频播放器的导航 View 。当我导航到视频时,播放器仅使用 AVPlayer(我不需要控件)自动播放视频。

但是,当我点击“后退”按钮并离开 PlayerView 时,视频不会停止播放。

如有任何关于如何解决此问题的想法,我们将不胜感激。

我已经将导航 View 、通过 VideoView 和 PlayerView 的代码包含在上下文中。 TIA。

导航 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代码

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)

最佳答案

这是一种可能的方法 - 在更新时使用演示模式,因为在这种情况下它是由于向后导航而更新的。

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

关于ios - 离开 View 时如何在 Swift 中停用 AVPlayer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63206932/

相关文章:

ios - UIScrollview 从第 3 页(共 5 页)开始,而不是从第 1 页(共 5 页)开始

objective-c - 将 Objective-C block 移植到 Swift

ios - SwiftUI:创建自定义警报

ios - 如何从父 View 向元素添加间距?

ios - SpriteKit位置困惑

ios - 尝试显示其 View 不在窗口层次结构警报中

ios - 调用 KeyboardDidHide 时无法更改 UIView 高度

ios - SwiftUI:有没有办法在点击时只折叠一个按钮而不是全部

html - index.html 未按 IOS 应用程序开发中的要求运行

swift - Swift 字符串中区分大小写的字符替换