SwiftUI VideoPlayer, change default black background/side space

Viewed 535

in SwiftUI I add a Videoplayer, but the frame is not really 16:9, but the video's are.

 private let player = AVPlayer(url: URL(string: UserDefaults.standard.string(forKey: "videoURL") ?? "https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4")!)
 

With this view:

ZStack {
    VideoPlayer(player: player)
       .onAppear() {
           player.play()
       }.frame(
            idealWidth: .infinity,
            maxWidth: .infinity,
            idealHeight: (UIScreen.main.bounds.height / 3) * 1.75,
            maxHeight: UIScreen.main.bounds.height - 600,
            alignment: .center
        )
    }
    .background(
        RoundedRectangle(cornerRadius: 40.0)
            .stroke(Color(.red), lineWidth: 5)
            .overlay(
                RoundedRectangle(cornerRadius: 40.0)
                    .fill(Color(.black))
            )
)

The Player is working and shown correctly, but with a black background on the both sides.. I want it red, so it does look prettier than random black in the red block.

Is there a way to change the background color of the black sideparts? I tried edgesIgnoringSafeArea with no luck.

Little but of how it looks like now, where you see the black "borders" on the side; see black side

1 Answers

Use AVPlayerLayer with the help of UIViewRepresentable and set the AVPlayerLayer layer color as you want.

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)
        playerLayer.backgroundColor = UIColor.red.cgColor // <--- Set color here
    }
}

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

Usage

struct ContentView: View {
    @State private var player = AVPlayer(url: URL(string: UserDefaults.standard.string(forKey: "videoURL") ?? "https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4")!)
    
    var body: some View {
        ZStack {
            PlayerView(player: $player)
                .onAppear() {
                    player.play()
                }.ignoresSafeArea()
        }
    }
}

EDIT

For video controller, use bellow code.

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

class PlayerUIView: UIView {
    
    // MARK: Class Property
    
    let playerViewController = AVPlayerViewController()
    
    // 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)
    }
    
    // MARK: Life-Cycle
    
    override func layoutSubviews() {
        super.layoutSubviews()
        playerViewController.view.frame = bounds
    }
    
    // MARK: Class Methods
    
    private func playerSetup(player: AVPlayer) {
        playerViewController.player = player
        playerViewController.view.backgroundColor = .red
        self.addSubview(playerViewController.view)
    }
}

You also do not need to set the background view.

Related