根据Apple的WWDC 2019 talk on the subject,AVPlayerViewController
应该以模块化方式显示,以利用API的所有最新全屏功能。这是建议的示例代码,可从当前的UIKit视图控制器调用该代码:
// Create the player
let player = AVPlayer(url: videoURL)
// Create the player view controller and associate the player
let playerViewController = AVPlayerViewController()
playerViewController.player = player
// Present the player view controller modally
present(playerViewController, animated: true)
这可以按预期工作,并以漂亮的全屏模式播放视频。
为了使用SwiftUI中的AVPlayerViewController
,我创建了UIViewControllerRepresentable
实现:
struct AVPlayerView: UIViewControllerRepresentable {
@Binding var videoURL: URL
private var player: AVPlayer {
return AVPlayer(url: videoURL)
}
func updateUIViewController(_ playerController: AVPlayerViewController, context: Context) {
playerController.player = player
playerController.player?.play()
}
func makeUIViewController(context: Context) -> AVPlayerViewController {
return AVPlayerViewController()
}
}
我似乎无法弄清楚如何直接从SwiftUI呈现此内容 与直接显示
AVPlayerViewController
的方式相同 从UIKit。我的目标仅仅是获得所有默认的全屏优势。
到目前为止,以下操作无效:
.sheet
修饰符并在图纸中显示它,则播放器将嵌入到图纸中,而不是全屏显示。 AVPlayerViewController
方法以模态形式呈现我的viewDidAppear
。这使播放器可以全屏显示,但是在显示视频之前,它还显示了一个空的视图控制器,我不希望用户看到它。 任何想法都将不胜感激!
答案 0 :(得分:5)
Razib-Mollick解释的解决方案对我来说是一个不错的开始,但是却没有使用SwiftUI .sheet()
方法。我通过将以下内容添加到ContentView
中来添加了此内容:
@State private var showVideoPlayer = false
var body: some View {
Button(action: { self.showVideoPlayer = true }) {
Text("Start video")
}
.sheet(isPresented: $showVideoPlayer) {
AVPlayerView(videoURL: self.$vURL)
.edgesIgnoringSafeArea(.all)
}
}
但是问题是,当SwiftUI重新渲染UI时,一次又一次实例化AVPlayer。
因此,AVPlayer的状态必须移到存储在环境中的class
对象中,因此我们可以从View struct
中获取它。因此,我的最新解决方案如下所示。我希望它可以帮助其他人。
class PlayerState: ObservableObject {
public var currentPlayer: AVPlayer?
private var videoUrl : URL?
public func player(for url: URL) -> AVPlayer {
if let player = currentPlayer, url == videoUrl {
return player
}
currentPlayer = AVPlayer(url: url)
videoUrl = url
return currentPlayer!
}
}
struct ContentView: View {
@EnvironmentObject var playerState : PlayerState
@State private var vURL = URL(string: "https://www.radiantmediaplayer.com/media/bbb-360p.mp4")
@State private var showVideoPlayer = false
var body: some View {
Button(action: { self.showVideoPlayer = true }) {
Text("Start video")
}
.sheet(isPresented: $showVideoPlayer, onDismiss: { self.playerState.currentPlayer?.pause() }) {
AVPlayerView(videoURL: self.$vURL)
.edgesIgnoringSafeArea(.all)
.environmentObject(self.playerState)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(PlayerState())
}
}
struct AVPlayerView: UIViewControllerRepresentable {
@EnvironmentObject var playerState : PlayerState
@Binding var videoURL: URL?
func updateUIViewController(_ playerController: AVPlayerViewController, context: Context) {
}
func makeUIViewController(context: Context) -> AVPlayerViewController {
let playerController = AVPlayerViewController()
playerController.modalPresentationStyle = .fullScreen
playerController.player = playerState.player(for: videoURL!)
playerController.player?.play()
return playerController
}
}
要注意的东西(一个错误?):每当使用.sheet()
显示一个模式表时,环境对象不会自动传递给子视图。必须使用environmentObject()
添加它们。
这是更多有关此问题的链接:https://oleb.net/2020/sheet-environment/
答案 1 :(得分:3)
如果想像UIKit这样全屏显示,您是否尝试过ContentView中的以下代码。
import SwiftUI
import UIKit
import AVKit
struct ContentView: View {
let toPresent = UIHostingController(rootView: AnyView(EmptyView()))
@State private var vURL = URL(string: "https://www.radiantmediaplayer.com/media/bbb-360p.mp4")
var body: some View {
AVPlayerView(videoURL: self.$vURL).transition(.move(edge: .bottom)).edgesIgnoringSafeArea(.all)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct AVPlayerView: UIViewControllerRepresentable {
@Binding var videoURL: URL?
private var player: AVPlayer {
return AVPlayer(url: videoURL!)
}
func updateUIViewController(_ playerController: AVPlayerViewController, context: Context) {
playerController.modalPresentationStyle = .fullScreen
playerController.player = player
playerController.player?.play()
}
func makeUIViewController(context: Context) -> AVPlayerViewController {
return AVPlayerViewController()
}
}
答案 2 :(得分:2)
Xcode 12·iOS 14
→使用error: expected unqualified-id before ‘<<’ token
17 | template <<int, typename> ...> struct FuncList {};
| ^~
代替.fullScreenCover
,一切就好。
另请参阅:How to present a full screen modal view using fullScreenCover