所以我按照教程-https://mobiraft.com/ios/for-gods-sake-can-you-autoplay-video-in-list-ios/
接下来,由于我们没有“固定”的视频内容(只是偶尔)我决定不实现这个集合,只是把它作为一个PlayerView类,我在Home View控制器中创建了一个var videoCells[IndexPath : HomeVideoCell]()
数组。当视图消失时,我清理了所有内容,因为我忘记了表单元格是重用的,然而,代码有一个deinit,应该删除它?我不太清楚为什么它需要再次加载内容,但无论如何。如果有人知道发生了什么事,我会喜欢一些帮助。我个人认为这是由于dequeueReusableCell,但我'我不确定滚动提要中的替代方案是什么
我用一个箭头指向它,但是错误层在PlayerView中,它说'if let layer = self.layer as?AVPlayerLayer
播放器视图
import Foundation
import UIKit
import AVKit
class PlayerView: UIView {
private var url: URL?
private var urlAsset: AVURLAsset?
private var playerItem: AVPlayerItem?
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
if shouldPlayImmediately {
DispatchQueue.main.async {
player.play()
}
}
}
}
func play() {
guard self.assetPlayer?.isPlaying == false else { return }
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()
}
}
}
首页VC相关零件
class HomeVC: UIViewController,UIScrollViewDelegate,MFMailComposeViewControllerDelegate,CLLocationManagerDelegate {
var videoCells = [IndexPath : HomeVideoCell]() //Variable is declared to be strong
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let videoCell = tableView.dequeueReusableCell(withIdentifier: "HomeVideoCell") as! HomeVideoCell
videoCell.selectionStyle = .none
videoCell.playerView = PlayerView()
videoCells[indexPath] = videoCell
print("Video cell found and created PlayerView")
// videoCell.img_thumb.roundCorners([.topLeft, .bottomLeft], radius: 10)
let str = self.bottomBannerData[indexPath.row]["video_thumb"]
let videoStr = self.bottomBannerData[indexPath.row]["video"]
print("strValue: \(String(describing: str)) -- videoStrValue: \(String(describing: videoStr))")
if videoStr != "" {
if let videoUrl = URL(string: "\(imageURL)\(videoStr!)") {
videoCell.playerView?.prepareToPlay(withUrl: videoUrl)
print("VIDEO CELL Set PlayerView with URL \(videoUrl)")
}
}
// if str != "" {
// let url:NSURL = NSURL(string :"\(imageURL)\(str!)")!
// videoCell.img_thumb.af.setImage(withURL: url as URL)
// }
print("VIDEO CELL DONE")
return videoCell
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
print("VDEO CELL VISIBLE")
if let videoCell = videoCells[indexPath] {
videoCell.playerView?.play()
print("VIDEO CELL PLAY!")
}
}
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if let videoCell = videoCells[indexPath] {
videoCell.playerView?.pause()
}
}
1条答案
按热度按时间juzqafwq1#
在本例中,似乎PlayerView示例在重用视频单元格时也被误用,从而加载了新内容。这是因为HomeVC类中的videoCells字典。此字典包含每个视频单元格的键-值对,单元格的索引用作键。但是,在tableView(_ tableView:UITableView,索引处的单元格行路径:IndexPath)-〉UITableViewCell函数,每渲染一个单元格,就会在字典中添加一个新的HomeVideoCell,这样当显示一个新的单元格时(使用willDisplay函数),对应的视频单元格就会播放PlayerView,但是当重复使用同一个单元格时,就会用相同的索引重新创建视频单元格,并创建一个新的PlayerView示例,从而加载新的内容。
要解决此问题,在重用视频单元格时,不应创建新的PlayerView示例来替换现有的PlayerView示例。相反,cellForRowAt函数应查找当前单元格的上一个视频单元格是否存在,如果存在,则应重用该单元格,而不是当前视频单元格。为此,需要如下更新代码:
我希望这能帮上忙。