2

Following is the code where I am trying to play videos by creating custom controls .

On click of the play button, the video in the table view plays but it also plays on the third cell from the current cell where the video is playing .

On moving to the third cell and clicking the play button there, it plays the correct video but again the same video plays two cells later.

How can I overcome this problem . Any help will be appreciated.

class ViewTableCell: UITableViewCell {
    var avPlayer: AVPlayer?
        var avPlayerLayer: AVPlayerLayer?
        var paused: Bool = false
        var videoPlayerItem: AVPlayerItem? = nil {
        didSet {

            avPlayer?.replaceCurrentItem(with: self.videoPlayerItem)
        }
    }

    var tapAction: ((ViewTableCell) -> Void)?

    @IBAction func playButtonAction(_ sender: UIButton) {
        tapAction?(self)
    }
func setupMoviePlayer(view:UIView){
        self.avPlayer = AVPlayer.init(playerItem: self.videoPlayerItem)
        avPlayerLayer = AVPlayerLayer(player: avPlayer)
        avPlayerLayer?.videoGravity = AVLayerVideoGravityResizeAspect
        avPlayer?.volume = 3
        avPlayer?.actionAtItemEnd = .none
        avPlayerLayer?.frame = view.bounds
        self.backgroundColor = .clear
        view.layer.insertSublayer(avPlayerLayer!, at: 0)

        let interval = CMTime(value: 1, timescale: 2)
        avPlayer?.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using :{ (progressTime) in
            let seconds = CMTimeGetSeconds(progressTime)

            if let duration = self.avPlayer?.currentItem?.duration{
                let durationSeconds = CMTimeGetSeconds(duration)
                self.videoSlider.value = Float(seconds/durationSeconds)
            }
        })

    }

    func stopPlayback(){
        self.avPlayer?.pause()
    }

    func startPlayback(){
        self.avPlayer?.play()
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        self.setupMoviePlayer(view: videoView)
        // Initialization code
    }
}

View Controller class

var cell : TrendViewTableCell?

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        //MARK CellForRowAt


        let resusableIdentifier: String = "ViewControllerCell"
        cell = (tableView.dequeueReusableCell(withIdentifier: resusableIdentifier) as? ViewTableCell)

        if cell == nil {
            cell = ViewTableCell(style:UITableViewCellStyle.default, reuseIdentifier: resusableIdentifier)
        }

        cell?.videoName.text = ArtistFeeds.sharedInstance.videoFeeds[indexPath.row].videoTitle
        cell?.tapAction = { (cell) in

            self.onTapPlayButton(cell)

        }
        cell?.playButton.addTarget(self, action: #selector(TrendViewController.onTapPlayButton), for: .touchUpInside)
        return cell!
    }

func onTapPlayButton(_ selectedCell:ViewTableCell){

        if let index = self.trendTableView.indexPath(for: selectedCell){
            //put your code to execute here
            let url = Bundle.main.path(forResource:ArtistFeeds.sharedInstance.videoFeeds[index.row].videoUrl, ofType:"mp4")

            let path = NSURL.fileURL(withPath: url!)
            let currentCell = tableView.cellForRow(at: index) as! ViewTableCell
            currentCell.videoPlayerItem = AVPlayerItem.init(url: path)
            let playImage = UIImage(named: "image_video_play") as UIImage?
            let pauseImage = UIImage(named: "image_video_pause") as UIImage?
            if currentCell.avPlayer?.rate == 1.0 {
                currentCell.stopPlayback()
                currentCell.playButton.setImage(playImage, for: .normal)

            } else {
                currentCell.startPlayback()
                currentCell.playButton.setImage(pauseImage, for: .normal)
            }
        }
    }
A.S
  • 798
  • 1
  • 10
  • 32
  • Cells are reused, so you are adding the tap handler multiple times as you scroll. You should handle the tap in cell class itself and notify the tableview controller via a delegation pattern or a closure; http://stackoverflow.com/questions/28659845/swift-how-to-get-the-indexpath-row-when-a-button-in-a-cell-is-tapped/38941510#38941510 – Paulw11 Apr 06 '17 at 06:00
  • I have implemented the above method you mentioned. But still the same problem persists. @Paulw11 – A.S Apr 06 '17 at 07:13

3 Answers3

1

You need to implement:

prepareForReuse()

on your cell, then inside this tell the AVPlayer to pause or replaceCurrentItem with nil or the new item

Sean Lintern
  • 3,103
  • 22
  • 28
0

Your tableview cells are reused, that's the reason you are facing such issue.

Manage it with some boolean value or resetting the video every time when in cellForRow: delegate.

DB_2016
  • 11
  • 2
0

it would be better you put cell?.playButton.addTarget(self, action: #selector(TrendViewController.onTapPlayButton), for: .touchUpInside) before the cell initiated.

In your case, you can put "cell?.playButton.addTarget(self, action: #selector(TrendViewController.onTapPlayButton)" in this part like this: if cell == nil { cell = ViewTableCell(style:UITableViewCellStyle.default, reuseIdentifier: resusableIdentifier) cell?.playButton.addTarget(self, action: #selector(TrendViewController.onTapPlayButton) } For me, I would override the initiate method in the cell class and do everything inside.

Ding Qiu
  • 64
  • 3