从URL Avplayer Swiftui加载时显示活动指示器和错误

发布于 2025-02-03 05:32:55 字数 3896 浏览 2 评论 0原文

我试图从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>) {
        
        
    }
}

I was trying to load short videos from a URL and I found the best way is to use AVPlayer, I found the code below but it didn't show the activity indicator also if the user doesn't have an internet it won't play the video. Thanks in advance.

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

This is the main screen which is 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)!)
    }
}

The button for control the video.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

七七 2025-02-10 05:32:55

SwiftUI视频播放器带有加载指示器

我创建了视频播放器,该视频播放器提供了基于SwiftUI的视频播放器组件,该视频播放器组件在视频加载时包含一个活动指示器。它利用Avkit和Avoundation Frameworks使用AvplayerviewController和UiActivityIndi​​catorView创建自定义Uiview。

代码

gist

import SwiftUI
import AVKit
import AVFoundation

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

用法

您可以在SwiftUI视图中使用VideoPlayer Struct,以轻松添加带有活动指示器的视频播放器。只需提供您想要播放的视频的URL即可。

struct ContentView: View {
    let videoURL = URL(string: "YOUR_VIDEO_URL_HERE")!
    var body: some View {
        VideoPlayer(videoURL: videoURL)
            .frame(height: 300)
    }
}

SwiftUI Video Player with Loading Indicator

I have created Video Player that provides a SwiftUI-based video player component that includes an activity indicator while the video is loading. It utilizes AVKit and AVFoundation frameworks to create a custom UIView with an AVPlayerViewController and a UIActivityIndicatorView.

Code

Here's the link to gist.

import SwiftUI
import AVKit
import AVFoundation

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

Usage

You can use the VideoPlayer struct in your SwiftUI views to easily add a video player with an activity indicator. Simply provide the URL of the video you want to play.

struct ContentView: View {
    let videoURL = URL(string: "YOUR_VIDEO_URL_HERE")!
    var body: some View {
        VideoPlayer(videoURL: videoURL)
            .frame(height: 300)
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文