As the title says, I've gotten my video player to work, but it shows the video on the right side of the cell instead of centered. Not sure why, I've tried a lot of things on the internet, and I know my code is probably not amazing, but I just want to center it horizontally and it refuses to work with me. If I turn off playerView.translatesAutoresizingMaskIntoConstraints = false
it just outright disappears
img_thumb
is an image that takes up the entirety of the space that will be a video thumbnail before it loads but right now is just a black background for the video, either way the full contentView has an additional element at the bottom so it's easier to use the img_thumb
constraints
playerView.frame = videoCell.img_thumb.frame
// playerView.layer.bounds = videoCell.img_thumb.bounds
// playerView.layer.frame = videoCell.img_thumb.frame
playerView.layer.position = CGPoint(x: videoCell.img_thumb.bounds.midX, y: videoCell.img_thumb.bounds.midY)
videoCell.contentView.addSubview(playerView)
playerView.translatesAutoresizingMaskIntoConstraints = false
playerView.bounds = videoCell.img_thumb.bounds
playerView.center = videoCell.img_thumb.center
playerView.centerXAnchor.constraint(equalTo: videoCell.img_thumb.centerXAnchor).isActive = true
playerView.centerYAnchor.constraint(equalTo: videoCell.img_thumb.centerYAnchor).isActive = true
playerView.heightAnchor.constraint(lessThanOrEqualTo: videoCell.img_thumb.heightAnchor).isActive = true
playerView.widthAnchor.constraint(lessThanOrEqualTo: videoCell.img_thumb.widthAnchor).isActive = true
The reason I use the UIImageView's constraints
The constraints for ContentView of HomeVideoCell
And finally what it actually looks like (with AutoLayout on)
and finally PlayerView
import Foundation
import UIKit
import AVKit
class PlayerView: UIView {
private var url: URL?
private var urlAsset: AVURLAsset?
private var playerItem: AVPlayerItem?
var loaded: Bool = false
var activityIndicator: UIActivityIndicatorView?
private var assetPlayer:AVPlayer? {
didSet {
DispatchQueue.main.async {
if let layer = self.layer as? AVPlayerLayer {
layer.player = self.assetPlayer
}
}
}
}
override class var layerClass: AnyClass {
return AVPlayerLayer.self
}
init() {
super.init(frame: .zero)
initialSetup()
}
required init?(coder: NSCoder) {
super.init(frame: .zero)
initialSetup()
}
private func initialSetup() {
if let layer = self.layer as? AVPlayerLayer {
// Do any configuration
layer.videoGravity = AVLayerVideoGravity.resizeAspect
}
}
func prepareToPlay(withUrl url:URL, shouldPlayImmediately: Bool = false) {
guard !(self.url == url && assetPlayer != nil && assetPlayer?.error == nil) else {
if shouldPlayImmediately {
play()
}
return
}
cleanUp()
self.url = url
let options = [AVURLAssetPreferPreciseDurationAndTimingKey : true]
let urlAsset = AVURLAsset(url: url, options: options)
self.urlAsset = urlAsset
let keys = ["tracks"]
urlAsset.loadValuesAsynchronously(forKeys: keys, completionHandler: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.startLoading(urlAsset, shouldPlayImmediately)
})
NotificationCenter.default.addObserver(self, selector: #selector(self.playerItemDidReachEnd), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
}
private func startLoading(_ asset: AVURLAsset, _ shouldPlayImmediately: Bool = false) {
var error:NSError?
let status: AVKeyValueStatus = asset.statusOfValue(forKey: "tracks", error: &error)
if status == AVKeyValueStatus.loaded {
let item = AVPlayerItem(asset: asset)
self.playerItem = item
let player = AVPlayer(playerItem: item)
self.assetPlayer = player
self.loaded = true
if shouldPlayImmediately {
DispatchQueue.main.async {
player.play()
}
}
}
}
func toggle() {
if self.assetPlayer?.isPlaying == false {
play()
} else {
pause()
}
}
func play() {
guard self.assetPlayer?.isPlaying == false else { return }
// if self.loaded && self.activityIndicator != nil {
// self.activityIndicator?.stopAnimating()
// }
DispatchQueue.main.async {
self.assetPlayer?.play()
}
}
func pause() {
guard self.assetPlayer?.isPlaying == true else { return }
DispatchQueue.main.async {
self.assetPlayer?.pause()
}
}
func cleanUp() {
pause()
urlAsset?.cancelLoading()
urlAsset = nil
assetPlayer = nil
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
}
deinit {
cleanUp()
}
@objc private func playerItemDidReachEnd(_ notification: Notification) {
guard notification.object as? AVPlayerItem == self.playerItem else { return }
DispatchQueue.main.async {
guard let videoPlayer = self.assetPlayer else { return }
videoPlayer.seek(to: .zero)
videoPlayer.play()
}
}
}
I as mentioned in comments it's really hard to figure out your problem. But try to replace the given code with this.Delete the block of code you shown me up, then replace it.
videoCell.contentView.addSubview(playerView)
playerView.translatesAutoresizingMaskIntoConstraints = false
playerView.centerXAnchor.constraint(equalTo: videoCell.img_thumb.centerXAnchor).isActive = true
playerView.centerYAnchor.constraint(equalTo: videoCell.img_thumb.centerYAnchor).isActive = true
playerView.heightAnchor.constraint(lessThanOrEqualTo: videoCell.img_thumb.heightAnchor).isActive = true
playerView.widthAnchor.constraint(lessThanOrEqualTo: videoCell.img_thumb.widthAnchor).isActive = true