当用户点击单元格中的播放按钮时,我尝试在UITableViewCell
中播放视频。
答案 0 :(得分:3)
场景1:
如果您愿意在每个单元格中自动播放Facebook或Instagram等视频,请考虑在AVPlayer
中添加cellForRowAtIndexPath
。
AVPlayer
一旦创建,将不允许您更改正在播放的网址(AVURLAsset
网址)。因此,如果您正在使用AVPlayer
并向玩家提供自己的观点,我恐怕每次在AVPlayer
中创建cellForRowAtIndexPath
实例都是唯一的解决方案。
另一方面,如果您打算使用AVPlayerViewController
,则可以在单元格AVPlayer
中创建viewController
awakeFromNib
个实例,这样您就只有一个每个单元格的玩家实例,cellForRowAtIndexPath
每次都可以传递不同的网址。您可以使用cell的prepareForReuse方法暂停播放器并重置所有播放器属性。
场景2:
如果您计划在用户点按单元格中的按钮后播放,请考虑在按钮上点击创建AVPlayer
/ AVPlayerViewController
并播放视频。使用prepareForReuse
重置播放器的属性,以确保在滚动和重复使用单元格时不会播放错误的视频。
修改强>
OP要求提供一些代码片段,提供骨架代码。这不是复制粘贴代码,想法只是想知道如何在单元格中使用AVPlayerViewController
代码可能有编译器问题。
//创建自定义tableViewCell
子类
class ImageTableViewCell: UITableViewCell {
@IBOutlet weak var carsImageView: UIImageView!
var playerController : AVPlayerViewController? = nil
var passedURL : URL! = nil
override func awakeFromNib() {
super.awakeFromNib()
playerController = AVPlayerViewController()
// Initialization code
}
func configCell(with url : URL) {
//something like this
self.passedURL = url
//show video thumbnail with play button on it.
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
@IBAction func playOrPauseVideo(_ sender: UIButton) {
let player = AVPlayer(url: url)
playerController.player = player
playerController?.showsPlaybackControls = true
playerController.player.play()
//add playerController view as subview to cell
}
override func prepareForReuse() {
//this way once user scrolls player will pause
self.playerController.player?.pause()
self.playerController.player = nil
}
}
上面的代码将PlayerController
设置为prepareForReuse()
中的nil,因此当用户滚动tableView
并且单元格退出tableView
Frame并重新使用时,播放器将暂停不会保留状态。如果您只是想在用户滚动回同一个单元格时暂停和重放,则必须将玩家保存在单元格外的某个位置,并找到将玩家实例映射到单元格的方法。
最后在cellForRowAtIndexPath
来电,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : ImageTableViewCell = tableView.dequeueReusableCell(withIdentifier: "imageCell") as! ImageTableViewCell
cell.configCell(with: URL(string: "https://google.com")!)
....
}
编辑2:
由于OP完全提出了在任何时间点只播放一个视频并暂停其他播放视频点击播放按钮的问题,我之前的回答将不再适用。
早期回答允许用户播放多个视频。
以下是修改后的答案,以使其有效。
修改您的自定义单元格类,如下所示。
protocol VideoPlayingCellProtocol : NSObjectProtocol {
func playVideoForCell(with indexPath : IndexPath)
}
class ImageTableViewCell: UITableViewCell {
@IBOutlet weak var carsImageView: UIImageView!
var playerController : AVPlayerViewController? = nil
var passedURL : URL! = nil
var indexPath : IndexPath! = nil
var delegate : VideoPlayingCellProtocol = nil
override func awakeFromNib() {
super.awakeFromNib()
playerController = AVPlayerViewController()
// Initialization code
}
func configCell(with url : URL,shouldPlay : Bool) {
//something like this
self.passedURL = url
if shouldPlay == true {
let player = AVPlayer(url: url)
if self.playerController == nil {
playerController = AVPlayerViewController()
}
playerController.player = player
playerController?.showsPlaybackControls = true
playerController.player.play()
}
else {
if self.playerController != nil {
self.playerController.player?.pause()
self.playerController.player = nil
}
//show video thumbnail with play button on it.
}
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
@IBAction func playOrPauseVideo(_ sender: UIButton) {
self.delegate.playVideoForCell(self.indexPath)
//add playerController view as subview to cell
}
override func prepareForReuse() {
//this way once user scrolls player will pause
self.playerController.player?.pause()
self.playerController.player = nil
}
}
在TableView VC中创建一个名为
的属性var currentlyPlayingIndexPath : IndexPath? = nil
让TableView VC确认VideoPlayingCellProtocol
extension ViewController : VideoPlayingCellProtocol {
func playVideoForCell(with indexPath: IndexPath) {
self.currentlyPlayingIndexPath = indexPath
//reload tableView
self.tableView.reloadRows(at: self.tableView.indexPathsForVisibleRows!, with: .none)
}
}
最后将cellForRowAtIndexPath
修改为
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : ImageTableViewCell = tableView.dequeueReusableCell(withIdentifier: "imageCell") as! ImageTableViewCell
//delegate setting here which u missed
cell.delegate = self
//let the cell know its indexPath
cell.indexPath = indexPath
cell.configCell(with: URL(string: "https://google.com")!, shouldPlay: self.currentlyPlayingIndexPath == indexPath)
....
}
这就是你所需要的一切。
答案 1 :(得分:3)
我有与您相似的要求,并在AVPlayer
中创建了全局AVPlayerLayer
和UITableViewController
变量。然后,当一个人选择了细胞时,我将它们连接到细胞上。从我所看到的情况来看,我的滚动很流畅,内存使用率很低,并且它还强制一次只播放一个视频。
第一步是在UITableViewController
:
lazy var avPlayer : AVPlayer = {
let player = AVPlayer()
return player
}()
lazy var avPlayerLayer : AVPlayerLayer = {
let layer = AVPlayerLayer(player: self.avPlayer)
return layer
}()
然后我在UITableViewController
中创建了两个函数来处理链接并从单元格中删除AVPlayerLayer
。
private func removePlayerFromCell()
{
if (self.avPlayerLayer.superlayer != nil)
{
self.avPlayerLayer.removeFromSuperlayer()
self.avPlayer.pause()
self.avPlayer.replaceCurrentItem(with: nil)
}
}
private func attachPlayerToCell(indexPath : IndexPath)
{
if let cell = tableView.cellForRow(at: indexPath)
{
self.removePlayerFromCell()
//create url
let url = ...
//create player item
let playerItem = AVPlayerItem(url: url)
self.avPlayer.replaceCurrentItem(with: playerItem)
self.avPlayerLayer.frame = cell.contentView.frame
cell.contentView.layer.addSublayer(self.avPlayerLayer)
self.avPlayer.play()
}
}
然后,您可以在attachPlayerToCell()
中致电didSelectRowAt()
。
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
attachPlayerToCell(indexPath: indexPath)
}
最后,要确保视频在滚动期间不播放,请使用表格UIScrollViewDelegate
停止播放:
override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
self.removePlayerFromCell()
}
希望这有帮助并且很清楚。