Here is the thing: I'm developing an app which consists in a feed on news (very similar to Instagram's feed), where I can display images and videos.
I configured a CollectionView which contains different cells (one for each item on the feed) and this cells have two types: VideoCell and ImageCell.
The Trouble I'm having is that Video cells contain an AVPlayer and inside of it, an AVPlayerItem which consumes a video from a given URL, and this videos are being displayed in black for a while until they start the playback.
What I want is to display an activityIndicator from the moment the cell is displayed until the moment the video is ready to start the playback.
I have heard that an observer could be useful but I don't know how to implement KVO since I'm somehow newbie on iOS development. This is my class:
// MARK: - VideoItemCollectionViewCell
final class VideoItemCollectionViewCell: MDCCardCollectionCell {
static let reuseIdentifier = "videoItem"
weak var delegate: NewsItemCellDelegate?
lazy var activityIndicator: UIActivityIndicatorView = {
let activityIndicator = UIActivityIndicatorView(style: UIActivityIndicatorView.Style.large)
activityIndicator.color = .vixonicColor
return activityIndicator
}()
private lazy var avPlayer: AVPlayer = AVPlayer(playerItem: nil)
private lazy var avPlayerLayer: AVPlayerLayer = {
let playerLayer = AVPlayerLayer(player: self.avPlayer)
playerLayer.videoGravity = .resize
return playerLayer
}()
var videoPlayerItem: AVPlayerItem? = nil {
didSet {
avPlayer.replaceCurrentItem(with: videoPlayerItem)
}
}
private var isSound = true {
didSet {
avPlayer.isMuted = !isSound
if isSound {
audioImageView.image = UIImage(named: "audio_enabled_icon")
} else {
audioImageView.image = UIImage(named: "audio_disabled_icon")
}
}
}
var dataSource: News? {
didSet {
guard let dataSource = dataSource else { return }
let dateDataSource = dataSource.creationDate ?? .empty
let dateAsDate = dateDataSource.toDate(with: "yyyy-MM-dd HH:mm:ss Z")
let dateAsString = dateAsDate?.toString(with: "dd MMMM")
let timeAsString = dateAsDate?.toString(with: "HH:mm")
let resourceId = dataSource.resourceId
likeButton.imageView?.contentMode = .scaleAspectFit
setLikeButton(using: resourceId)
if !dataSource.buttons.indices.contains(0) {
leftButton.isHidden = true
} else {
leftButton.setTitle(dataSource.buttons[0].text, for: .normal)
}
if !dataSource.buttons.indices.contains(1) {
rightButton.isHidden = true
} else {
rightButton.setTitle(dataSource.buttons[1].text, for: .normal)
}
startActivityIndicator()
dateLabel.text = "\(dateAsString ?? "") a las \(timeAsString ?? "")"
likeCounterLabel.text = String(dataSource.interactions?.likeCount ?? 0)
let urlString = dataSource.mediaUrl ?? ""
if let url = URL(string: urlString) {
videoPlayerItem = AVPlayerItem(url: url)
setupMoviePlayer()
}
}
}
}
// MARK: - Video Utils
extension VideoItemCollectionViewCell {
func setupMoviePlayer() {
avPlayer.volume = 1
avPlayer.actionAtItemEnd = .none
avPlayerLayer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: videoView.frame.size.height)
self.backgroundColor = .none
videoView.layer.addSublayer(avPlayerLayer)
NotificationCenter.default.addObserver(self,
selector: #selector(playerItemDidReachEnd(notification:)),
name: .AVPlayerItemDidPlayToEndTime,
object: avPlayer.currentItem)
isSound = false
stopActivityIndicator()
avPlayer.play()
}
func stopPlayback() { avPlayer.pause() }
func startPlayback() { avPlayer.play() }
func toggleVideoAudio() { isSound.toggle() }
}
Thank you very much