I try to play video in UITableViewCell when a user clicks on play button in cell.
What is the best place to add AVPlayer or MPMoviePlayerController in UITableViewCell?
6.6k Views Asked by Pankil At
2
There are 2 best solutions below
0
On
I had a similar requirement as you and created global AVPlayer and AVPlayerLayer variables in my UITableViewController. I then attached them to a cell when a person selected the cell. From what I've seen, my scrolling is smooth, memory usage is minimal, and it also enforces that only one video is played at a time.
First step was to create the variables in my UITableViewController:
lazy var avPlayer : AVPlayer = {
let player = AVPlayer()
return player
}()
lazy var avPlayerLayer : AVPlayerLayer = {
let layer = AVPlayerLayer(player: self.avPlayer)
return layer
}()
I then created two functions in the UITableViewController to handle linking and removing the AVPlayerLayer from a cell as such.
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()
}
}
You can then call attachPlayerToCell() in didSelectRowAt().
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
attachPlayerToCell(indexPath: indexPath)
}
Lastly, to ensure videos don't play during scrolling, use the table's UIScrollViewDelegate to stop playback:
override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
self.removePlayerFromCell()
}
Hope this helps and is clear.
Scene 1:
If you are willing to auto play video's like Facebook or Instagram in each cell then consider adding
AVPlayerincellForRowAtIndexPath.AVPlayerwill not allow you to change the url being played (AVURLAsseturl) once created. So If you are usingAVPlayerand providing ur own view to player I afraid creatingAVPlayerinstance every time incellForRowAtIndexPathis the only solution.On the other hand if you are planning to use
AVPlayerViewController, you can createAVPlayerviewControllerinstance in cell'sawakeFromNibso you will have only one instance of player per cell and incellForRowAtIndexPathyou can pass different url each time. You can use prepareForReuse method of cell to pause the player and resetting all your player properties.Scene 2:
If you are planning to play once user taps on button in cell, consider creating
AVPlayer/AVPlayerViewControlleron button tap and play the video. UseprepareForReuseto reset the properties of ur player to ensure you don't play wrong video when u scroll and cell gets reused.EDIT:
As OP has asked for some code snippet, providing skeleton code. This is not a copy paste code, idea is just to give idea of how to use
AVPlayerViewControllerinside cell the code might have compiler issues.//create a custom
tableViewCellsubclassThe code above sets the
PlayerControllerto nil inprepareForReuse()so when user scrolls thetableViewand cell goes out oftableViewFrame and gets reused, player will pause and will not retain the status. If you simply want to pause and replay when user scrolls back to the same cell u will have to save player somewhere outside the cell and find a way to map player instance to cell.Finally in
cellForRowAtIndexPathcall,EDIT 2:
As OP has completely filped the question to play only one video at any point in time and pause other playing videos on tapping play button my earlier answer will no longer hold true.
Earlier answer allows user to play multiple video.
Here is a modified answer to make it work.
Modify your custom cell class as below.
In your TableView VC create a property called
Make your TableView VC to confirm VideoPlayingCellProtocol
Finally modify your
cellForRowAtIndexPathasThats all you need.