I'm trying to create a looping video in SwiftUI that will only display once the video is fully loaded. To highlight the issue, I have a blue rectangle in a ZStack under the video when the asset is ready. When the asset is ready, it will show the blue rectangle for a brief second before the video starts to play. I'm not sure how to get it perfect. Here is my code so far.
I also tried to do this with VideoPlayer in SwiftUI, but I couldn't figure out how to get a looping video with an aspect fill ratio.
import SwiftUI
import AVKit
class PlayerView: UIView {
private let playerItem: AVPlayerItem
private let player: AVPlayer
private var playerLayer: AVPlayerLayer
init(asset: AVAsset) {
playerItem = AVPlayerItem(asset: asset)
player = AVPlayer(playerItem: playerItem)
playerLayer = AVPlayerLayer(player: player)
super.init(frame: CGRectZero)
player.play()
playerLayer.videoGravity = .resizeAspectFill
self.layer.addSublayer(playerLayer)
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue: nil) { _ in
self.player.seek(to: .zero)
self.player.play()
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
playerLayer.frame = bounds
}
}
struct LoopingVideoPlayer: UIViewRepresentable {
var asset: AVAsset
func makeUIView(context: Context) -> PlayerView {
PlayerView(asset: asset)
}
func updateUIView(_ uiView: PlayerView, context: Context) {
}
}
struct ContentView: View {
@State var video: AVAsset?
var body: some View {
ZStack {
if let video {
Rectangle()
.foregroundStyle(.blue)
LoopingVideoPlayer(asset: video)
}
Button("Start") {
Task {
guard let url = URL(string: "https://www.apple.com/105/media/us/apple-vision-pro/2024/6e1432b2-fe09-4113-a1af-f20987bcfeee/anim/experience-apps/large.mp4") else {
return
}
let asset = AVAsset(url: url)
let _ = try await asset.load(.isPlayable)
video = asset
}
}
}
}
}
#Preview {
ContentView()
}
Give this a try:
Notice the new function
observeValue()which checks if the videos status isreadyToPlayonly then it would play it.