从VStack(SwiftUI)删除AVPlayer后,音频继续播放

时间:2020-11-06 08:06:33

标签: ios swift macos swiftui

我有以下包含AVPlayer(在PlayerView中)的VStack:

struct ContentView: View {
    @State var url: URL?
    private let openFile = NotificationCenter.default.publisher(for: .openFile)

    var body: some View {
        VStack {
            if isVideo(self.url!) {
                PlayerView(url: self.url!)
            } else {
                Image(nsImage: NSImage(contentsOf: self.url!)!).resizable().aspectRatio(contentMode: .fit)
            }

        }.onReceive(openFile) { notification in
            self.url = notification.object as? URL
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

这是PlayerView:

struct PlayerView: NSViewRepresentable {
    private var url: URL
    init(url: URL) {
        self.url = url
    }

    func updateNSView(_ nsView: PlayerNSView, context _: NSViewRepresentableContext<PlayerView>) {
        nsView.play(url: url)
    }

    func makeNSView(context _: Context) -> PlayerNSView {
        PlayerNSView(frame: .zero)
    }

    func dismantleNSView(coordinator _: Coordinator) {
        // not called
    }
}

从视频更新为图像后,视频的音频会持续播放几秒钟。

我在哪里可以告诉AVPlayer暂停? VStack是否会通知VideoPlayer?


已使用iUrii中的代码进行了更新:

struct ContentView: View {
    @State var url: URL?
    @State var playerView: PlayerView?

    private let openFile = NotificationCenter.default.publisher(for: .openFile)

    var body: some View {
        VStack {
            if let view = playerView {
                view
            } else {
                Image(nsImage: NSImage(contentsOf: self.url!)!).resizable().aspectRatio(contentMode: .fit)
            }

        }.onReceive(openFile) { notification in
            url = notification.object as? URL

            if playerView != nil {
                playerView!.player.pause()
                playerView = nil
            }
            if videoExtensions.contains(url!.pathExtension.lowercased()) {
                playerView = PlayerView(url: url!)
            }
        }
    }
}

当将视频从图像转换为视频时,这非常有用。

当我将视频转为视频时,第一个视频将暂停,而第二个视频中的音频将开始播放,尽管它​​没有显示(第一个视频仍然可见)。


我通过用playerView.player.replaceCurrentItem(with: playerItem)更新播放器而不是替换视图来解决了这个问题。

1 个答案:

答案 0 :(得分:2)

如果要控制其行为,例如,应使用PlayerNSView手动管理AVPlayer

struct PlayerView: NSViewRepresentable {
    let player: AVPlayer
    
    init(url: URL) {
        self.player = AVPlayer(url: url)
    }
    
    func updateNSView(_ nsView: AVPlayerView, context: NSViewRepresentableContext<Self>) {
    }

    func makeNSView(context: NSViewRepresentableContext<Self>) -> AVPlayerView {
        let playerView = AVPlayerView(frame: .zero)
        playerView.player = player
        return playerView
    }
}

struct ContentView: View {
    @State var playerView: PlayerView?
    
    var body: some View {
        VStack {
            if let view = playerView  {
                view
            } else {
                Image(nsImage: NSImage(named: "iphone12")!)
            }
            
            Button("Toogle") {
                if playerView == nil {
                    let url = URL(string: "https://www.apple.com/105/media/us/iphone-12-pro/2020/e70ffbd8-50f1-40f3-ac36-0f03a15ac314/films/product/iphone-12-pro-product-tpl-us-2020_16x9.m3u8")!
                    playerView = PlayerView(url: url)
                    playerView?.player.play()
                }
                else {
                    playerView?.player.pause()
                    playerView = nil
                }
            }
        }
    }
}
相关问题