在 SwiftUI 中更改 AVPlayer 源? [英] Change AVPlayer source in SwiftUI?

查看:58
本文介绍了在 SwiftUI 中更改 AVPlayer 源?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 AVPlayer,可以在我的 SwiftUI 应用程序的后台播放视频,效果很好.

I have an AVPlayer that plays a video in the background of my SwiftUI app which works fine.

但我需要允许用户通过点击/点击按钮来更改视频.

But I need to allow the users to change the video on a button tap/click.

这是我播放视频的代码:

This is my code for playing video:

var player = AVPlayer()
var bgVideoURL = "https://www.w3schools.com/html/movie.mp4"


struct PlayerView: UIViewRepresentable {
    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PlayerView>) {
    }

    func makeUIView(context: Context) -> UIView {
        return PlayerUIView(frame: .zero)
    }
}

class PlayerUIView: UIView {

    private let playerLayer = AVPlayerLayer()

    override init(frame: CGRect) {
        super.init(frame: frame)

        let url = URL(string: bgVideoURL)!
        player = AVPlayer(url: url)
        player.actionAtItemEnd = .none
        
        player.play()

        playerLayer.player = player
        playerLayer.videoGravity = .resizeAspectFill

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(playerItemDidReachEnd(notification:)),
                                               name: .AVPlayerItemDidPlayToEndTime,
                                               object: player.currentItem)

        layer.addSublayer(playerLayer)
    }
    
    

    @objc func playerItemDidReachEnd(notification: Notification) {
        if let playerItem = notification.object as? AVPlayerItem {
            playerItem.seek(to: .zero, completionHandler: nil)
        }
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        playerLayer.frame = bounds
    }
}

这就是我播放视频的方式:

and this is how I play the video:

var body: some View {
    PlayerView()
    .edgesIgnoringSafeArea(.all)
}

我需要在按钮点击/点击时更改视频,所以我尝试了这个:

I need to change the video on button click/tap so I tried this:

 .onTapGesture {

   player.pause()
   player.seek(to: .zero)

   bgVideoURL = "https://media.w3.org/2010/05/sintel/trailer.mp4"

   player.play()
                                        
   }

以上代码会重启player,但不会改变播放器的视频/源!

The above code will restart the player but it doesn't change the video/source of the player!

还有什么我需要做的吗?

Is there something else I need to do?

推荐答案

首先创建一个合适的PlayerUIView类(移除全局变量等)

First, create a proper PlayerUIView class (Remove global variables, etc.)

PlayerUIView

PlayerUIView

class PlayerUIView: UIView {
    
    // MARK: Class Property
    
    let playerLayer = AVPlayerLayer()
    
    // MARK: Init
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    init(player: AVPlayer) {
        super.init(frame: .zero)
        self.playerSetup(player: player)
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    // MARK: Life-Cycle
    
    override func layoutSubviews() {
        super.layoutSubviews()
        playerLayer.frame = bounds
    }
    
    // MARK: Class Methods
    
    private func playerSetup(player: AVPlayer) {
        playerLayer.player = player
        player.actionAtItemEnd = .none
        layer.addSublayer(playerLayer)
        
        self.setObserver()
    }
    
    func setObserver() {
        NotificationCenter.default.removeObserver(self)
        NotificationCenter.default.addObserver(self, selector: #selector(playerItemDidReachEnd(notification:)),
                                               name: .AVPlayerItemDidPlayToEndTime,
                                               object: playerLayer.player?.currentItem)
    }
    
    @objc func playerItemDidReachEnd(notification: Notification) {
        if let playerItem = notification.object as? AVPlayerItem {
            playerItem.seek(to: .zero, completionHandler: nil)
            self.playerLayer.player?.play()
        }
    }
}

现在,使用 @Binding 在 PlayerView 中绑定你的播放器

Now, use @Binding to bind your player in PlayerView

玩家视图

struct PlayerView: UIViewRepresentable {
    
    @Binding var player: AVPlayer
    
    func makeUIView(context: Context) -> PlayerUIView {
        return PlayerUIView(player: player)
    }
    
    func updateUIView(_ uiView: PlayerUIView, context: UIViewRepresentableContext<PlayerView>) {
        uiView.playerLayer.player = player
        
        //Add player observer.
        uiView.setObserver()
    }
}

最后,在内容视图中创建 AVPlayer 对象,使用 AVPlayer 更改您的新 URL.

in last, inside the content view make AVPlayer object, change your new URL with AVPlayer.

struct PlayerContentView: View {
    
    @State private var player = AVPlayer(url: URL(string: "https://media.w3.org/2010/05/sintel/trailer.mp4")!)
    
    var body: some View {
        PlayerView(player: $player)
            .onTapGesture {
                player.pause()
                player.seek(to: .zero)
                
                player = AVPlayer(url: Bundle.main.url(forResource: "temp_video", withExtension: "mp4")!) // or AVPlayer(url: URL(string: "https://media.w3.org/2010/05/sintel/trailer.mp4")!)
                player.play()
                
            }
            .onAppear {
                player.play()
            }
        .edgesIgnoringSafeArea(.all)
    }
}

这篇关于在 SwiftUI 中更改 AVPlayer 源?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆