如何在 SwiftUI 中使用 VStack 显示 AVPlayer?

7
我创建了一个简单的AVPlayer。(如果我没有正确创建,请帮我修复...)我想在我的Swift UI中显示它,但是我有点卡住了...
如果库中至少有AVPlayer View组件,那么这将会更容易,但我在库中没有找到它...
这是我的代码在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

顺便说一下,如果有一个展示如何使用Swift UI制作视频播放器的教程,我会非常感激!补充一下,我正在开发一款macOS应用。

我该如何使用类似于PlayerView("video1.mp4")和PlayerView("video2.mp4")的函数? - q8yas
2个回答

13
当然,这里是由Chris Mash on Medium提供的教程。
基本上,您需要将AVPlayerLayer嵌入到符合UIViewRepresentable协议的结构体中,对于您想要在SwiftUI中使用的任何UIView组件,都需要这样做。
struct PlayerView: UIViewRepresentable {
  func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PlayerView>) {
  }

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

实现的“核心”在PlayerUIView类中完成:

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

然后你可以像这样使用它:

var body: some View {
  PlayerView()
}

抱歉,我在最初的帖子中忘记提到了这一点... :) - Francis Dolbec
@FrancisDolbec:UIViewRepresentableAVPlayerLayer在MacOS上也可以使用。 - Bogdan Farca
哦,真的吗?也许是我打错了什么,因为当我尝试使用你的答案时,它说无法导入UIKit...而且我读到它是用于iOS的,相当于AppKit... - Francis Dolbec
@FrancisDolbec:抱歉,我是指NSViewRepresentable,请参见https://developer.apple.com/documentation/swiftui/nsviewrepresentable。 - Bogdan Farca
我该如何使用类似于PlayerView("video1.mp4") PlayerView("video2.mp4")的代码? - q8yas
显示剩余8条评论

4

感谢Bogdan快速回答并提供教程链接!

这里是将代码转换为NSView,以便于macOS应用程序运行的代码...

以下是结构体PlayerView

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

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

这是“the meat"类,就像Bogdan所说:

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

最后,您可以使用PlayerView()将AVPlayer添加到struct ContentView中。

PlayerUIView的实现对我来说非常好用,在macOS Catalina上开箱即用。使用已开启macOS的iOS应用程序。 - Jonny
我该如何使用类似于PlayerView("video1.mp4") PlayerView("video2.mp4")的代码? - q8yas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接