import AVKit import UIKit protocol VideoViewDelegate { func didEndVideo() func didEndVideo(of instance: VideoView) func isVideoReady() } class VideoView: UIView { var playerLayer: AVPlayerLayer? var player: AVPlayer? var isLoop: Bool = false var delegate: VideoViewDelegate! var observer: NSKeyValueObservation? override init(frame: CGRect) { super.init(frame: frame) backgroundColor = .black } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } func ply(for url: URL) { player = AVPlayer(url: url) playerLayer = AVPlayerLayer(player: player) playerLayer?.frame = bounds playerLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill if let playerLayer = self.playerLayer { layer.addSublayer(playerLayer) } NotificationCenter.default.addObserver(self, selector: #selector(reachTheEndOfTheVideo), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem) } func prepare(url: URL) { player?.replaceCurrentItem(with: AVPlayerItem(url: url)) NotificationCenter.default.addObserver(self, selector: #selector(reachTheEndOfTheVideo), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem) } func destroyMe() { stop() NotificationCenter.default.removeObserver(self) observer?.invalidate() } func play() { if player?.timeControlStatus != AVPlayer.TimeControlStatus.playing { player?.play() } } func pause() { player?.pause() } func stop() { player?.pause() player?.seek(to: CMTime.zero) } @objc func reachTheEndOfTheVideo(_ notification: Notification) { if isLoop { player?.pause() player?.seek(to: CMTime.zero) player?.play() } else { player?.pause() player?.seek(to: CMTime.zero) UIView.animate(withDuration: 0.4) { [weak self] in self!.transform = .identity } if delegate != nil { delegate.didEndVideo() } if delegate != nil { delegate.didEndVideo(of: self) } } } }