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()
}
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?
First, create a proper PlayerUIView class (Remove global variables, etc.)
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()
}
}
}
Now, use @Binding to bind your player in PlayerView
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()
}
}
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)
}
}
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