我试图从 URL 加载短视频,我发现最好的方法是使用 AVPlayer,我找到了下面的代码,但它没有显示活动指示器,如果用户没有互联网,它也不会显示播放视频。预先感谢。
import SwiftUI
import AVKit
struct ContentView: View {
@State var player = AVPlayer(url: URL(string: "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4")!)
@State var isplaying = false
@State var showcontrols = false
@State var value : Float = 0
var body: some View {
VStack{
ZStack{
VideoPlayer(player: $player)
if self.showcontrols{
Controls(player: self.$player, isplaying: self.$isplaying, pannel: self.$showcontrols,value: self.$value)
}
}
.frame(height: UIScreen.main.bounds.height / 3.5)
.onTapGesture {
self.showcontrols = true
}
GeometryReader{_ in
VStack{
Text("Custom Video Player").foregroundColor(.white)
}
}
}
.background(Color.black.edgesIgnoringSafeArea(.all))
.onAppear {
self.player.play()
self.isplaying = true
}
}
}
这是主屏幕,即ContentView
struct Controls : View {
@Binding var player : AVPlayer
@Binding var isplaying : Bool
@Binding var pannel : Bool
@Binding var value : Float
var body : some View{
VStack{
Spacer()
HStack{
Button(action: {
if self.isplaying{
self.player.pause()
self.isplaying = false
}
else{
self.player.play()
self.isplaying = true
}
if self.player.currentItem?.duration.seconds == self.player.currentTime().seconds{
print("did it")
self.player.seek(to: CMTime.zero)
self.player.play()
self.isplaying = true
}
}) {
Image(systemName: self.isplaying ? "pause.fill" : "play.fill")
.font(.title)
.foregroundColor(.white)
.padding(20)
}
}
}.padding()
.onTapGesture {
self.pannel = false
}
}
func getSliderValue()->Float{
return Float(self.player.currentTime().seconds / (self.player.currentItem?.duration.seconds)!)
}
func getSeconds()->Double{
return Double(Double(self.value) * (self.player.currentItem?.duration.seconds)!)
}
}
控制视频的按钮。
class Host : UIHostingController<ContentView>{
override var preferredStatusBarStyle: UIStatusBarStyle{
return .lightContent
}
}
struct VideoPlayer : UIViewControllerRepresentable {
@Binding var player : AVPlayer
func makeUIViewController(context: UIViewControllerRepresentableContext<VideoPlayer>) -> AVPlayerViewController {
let controller = AVPlayerViewController()
controller.player = player
controller.showsPlaybackControls = false
controller.videoGravity = .resize
return controller
}
func updateUIViewController(_ uiViewController: AVPlayerViewController, context: UIViewControllerRepresentableContext<VideoPlayer>) {
}
}
我创建了视频播放器,它提供了一个基于 SwiftUI 的视频播放器组件,其中包含视频加载时的活动指示器。它利用 AVKit 和 AVFoundation 框架创建带有 AVPlayerViewController 和 UIActivityIndicatorView 的自定义 UIView。
这是要点的链接。
import SwiftUI
import AVKit
struct VideoPlayer: UIViewRepresentable {
var videoURL: URL
let videoPlayerView = ActivityIndicatorPlayer()
func makeUIView(context: Context) -> ActivityIndicatorPlayer {
let player = AVPlayer(url: videoURL)
videoPlayerView.setPlayer(player: player)
videoPlayerView.startLoading()
player.addObserver(context.coordinator, forKeyPath: "status", options: [.old, .new], context: nil)
return videoPlayerView
}
func updateUIView(_ uiView: ActivityIndicatorPlayer, context: Context) {}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject {
var parent: VideoPlayer
init(_ parent: VideoPlayer) {
self.parent = parent
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "status", let change = change, let newValue = change[NSKeyValueChangeKey.newKey] as? Int {
if newValue == AVPlayer.Status.readyToPlay.rawValue {
parent.videoPlayerView.stopLoading()
}
}
}
}
}
class ActivityIndicatorPlayer: UIView {
private let playerViewController = AVPlayerViewController()
private let activityIndicator = UIActivityIndicatorView(style: .large)
override init(frame: CGRect) {
super.init(frame: frame)
configurePlayerView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
configurePlayerView()
}
private func configurePlayerView() {
addSubview(playerViewController.view)
addSubview(activityIndicator)
playerViewController.view.translatesAutoresizingMaskIntoConstraints = false
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
playerViewController.view.topAnchor.constraint(equalTo: topAnchor),
playerViewController.view.leadingAnchor.constraint(equalTo: leadingAnchor),
playerViewController.view.trailingAnchor.constraint(equalTo: trailingAnchor),
playerViewController.view.bottomAnchor.constraint(equalTo: bottomAnchor),
activityIndicator.centerXAnchor.constraint(equalTo: centerXAnchor),
activityIndicator.centerYAnchor.constraint(equalTo: centerYAnchor)
])
}
func setPlayer(player: AVPlayer?) {
playerViewController.player = player
}
func startLoading() {
activityIndicator.startAnimating()
}
func stopLoading() {
activityIndicator.stopAnimating()
}
}