Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to show my AVPlayer in a VStack with SwiftUI

I have created a simple AVPlayer. (If I didn't create it correctly, please help me fixing it... 😀 ) I want to display it in my VStack with swift ui, but I'm kind of stuck...

If at least there was the AVPlayer View component in the library, it would have been easier, but I didn't found it in the library... 😔

Here is my code in the ContentView.swift:

//
//  ContentView.swift
//  test
//
//  Created by Francis Dolbec on 2019-06-26.
//  Copyright © 2019 Francis Dolbec. All rights reserved.
//

import SwiftUI
import AVKit
import AVFoundation

// MARK: variables
var hauteurMenuBar = NSApplication.shared.mainMenu?.menuBarHeight
var urlVideo = URL(string: "/Users/francisdolbec/Movies/Séries Télé/Rick et Morty/Rick.and.Morty.S01E01.VFQ.HDTV.1080p.x264-Kamek.mp4")
let player = AVPlayer(url: urlVideo!)


struct ContentView : View {
    var body: some View {

        VStack {
            Text("Hello World")
                .frame(maxWidth: .infinity, maxHeight: .infinity)
            Text("PATATE!")
            //player.play()
            }

        .frame(minWidth: 1024, idealWidth: 1440, maxWidth: .infinity, minHeight: (640-hauteurMenuBar!), idealHeight: (900-hauteurMenuBar!), maxHeight: .infinity)

    }
}


#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif

By the way, if there's a tutorial that show how to make a video player with swift ui, I would really appreciate it!

EDIT I forgot to say that I am developing a macOS app.

like image 585
Francis Dolbec Avatar asked Jun 30 '19 06:06

Francis Dolbec


2 Answers

Sure, here's the tutorial, by Chris Mash on Medium.

Basically you embed an AVPlayerLayer into a struct conforming to UIViewRepresentable, something you'll do for any UIView component you want to use with SwiftUI.

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

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

The "meat" of the implementation is done in the PlayerUIView class:

class PlayerUIView: UIView {
  private let playerLayer = AVPlayerLayer()

  override init(frame: CGRect) {
    super.init(frame: frame)
    
    let url = URL(string: "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8")!
    let player = AVPlayer(url: url)
    player.play()
    
    playerLayer.player = player
    layer.addSublayer(playerLayer)
  }

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

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

And then you use it like this:

var body: some View {
  PlayerView()
}
like image 113
Bogdan Farca Avatar answered Jan 04 '23 05:01

Bogdan Farca


Thanks to Bogdan for the quick answer and for the like to the tutorial!

Here is the code, converted to NSView so it could work for macOS apps...

Here is the struct PlayerView :

struct PlayerView: NSViewRepresentable {
    func updateNSView(_ nsView: NSView, context: NSViewRepresentableContext<PlayerView>) {

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

Here is the class, "the meat" like Bogdan said:

class PlayerNSView: NSView{
    private let playerLayer = AVPlayerLayer()

    override init(frame:CGRect){
        super.init(frame: frame)
        let urlVideo = URL(string: "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8")!
        let player = AVPlayer(url: urlVideo)
        player.play()
        playerLayer.player = player
        if layer == nil{
            layer = CALayer()
        }
        layer?.addSublayer(playerLayer)
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func layout() {
        super.layout()
        playerLayer.frame = bounds
    }
}

Finally you can use PlayerView() to add the AVPlayer in the struct ContentView.

like image 38
Francis Dolbec Avatar answered Jan 04 '23 05:01

Francis Dolbec