Search code examples
iosxcodeuitableviewuicollectionviewavplayer

How to Pause the video when scrolling and Play a video when cell is visible on the screen Swift


I have a table view cell for vertical listing and have added a collection view in a horizontal playlist. I want to implement video playback similar to the YouTube app. Specifically, I aim to have the video play when the cell is properly visible and pause when it becomes invisible in the collection view. I'm using AVPlayer. I've almost finished, but I'm facing one issue. Please check the code.

For example, the collection view array:

Table array:-   [Test:[video.mp4, image.jpg, image.jpg, image.jpg, image.jpg, image.jpg, video.mp4],Test2:[video.mp4, image.jpg, image.jpg, image.jpg, image.jpg, image.jpg, video.mp4],Test3:[video.mp4, image.jpg, image.jpg, image.jpg, image.jpg, image.jpg, video.mp4]]

Collection array:-   [video.mp4, image.jpg, image.jpg, image.jpg, image.jpg, image.jpg, video.mp4]

When the app runs, it will automatically display and check if it contains an mp4 file, then play the video automatically and pause when the video duration finishes. The issue I'm facing is that when we scroll vertical(Scroll Tablview) through the screen and reach index 2 or 3, the last video automatically plays.

Code:-

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    stringArrayUrl.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VideoCell", for: indexPath) as! VideoCell
    if stringArrayUrl[indexPath.item].contains(".mp4") || stringArrayUrl[indexPath.item].contains(".MP4") {
        cell.videoMainView.isHidden = false
        cell.videoThumbImg.getThumbnailImageFromVideoUrl(url: URL(string: self.stringArrayUrl[indexPath.item])!) { (thumbNailImage) in
            cell.videoThumbImg.image = thumbNailImage
        }
        cell.imgPlayBtn.actionBlock {
            self.playVideoWhileScrlling(cell: cell, indexPath: indexPath)
        }
    }
    return cell
}

 func playVideoWhileScrlling(cell:StoryTableImageCell,indexPath:IndexPath){
    if self.stringArrayUrl.indices.contains(indexPath.item+1) {
        self.checkNextVideoUrlIsAvalibleOrNot(indexPath: indexPath.item)
    }
    cell.videoPlayerView.isHidden = false
    self.returnVideoPlayer(inputUrl: self.stringArrayUrl[indexPath.item])
}

func returnVideoPlayer(inputUrl:String) {
    let playerItem = AVPlayerItem(url: URL(string: inputUrl)!)
    videoPlayer.replaceCurrentItem(with: playerItem)
    videoPlayer.play()
}

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    if let cell = cell as? VideoCell {
        if stringArrayUrl[indexPath.item].contains(".mp4") || stringArrayUrl[indexPath.item].contains(".MP4") {
            playVideoWhileScrlling(cell: cell, indexPath: indexPath)
        }
    }
}

ScreenShot

Question: How to pause the video when scrolling and Play a video when cell is visible on the screen. ?

Can someone please explain to me how to do this, I've tried with the above code but have no results yet. Please Correct me if I'm doing wrong.

Any help would be greatly appreciated


Solution

  • Table View Code
    
     func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
            scrollToMostVisibleCell()
        }
        
        func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
            if !decelerate{
                scrollToMostVisibleCell()
            }
        }
        
        func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "stopvideo"), object: nil)
        }
        
        func scrollToMostVisibleCell() {
            let visibleRect = CGRect(origin: tableVW.contentOffset, size: tableVW.bounds.size)
            let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
            guard let visibleIndexPath = tableVW.indexPathForRow(at: visiblePoint) else { return }
            
            if let cell = tableVW.cellForRow(at: visibleIndexPath) as? FeedBookTVC {
                let convertedRect = tableVW.convert(cell.frame, to: cell.collectionVW)
                if let visibleCollectionViewIndexPath = cell.collectionVW.indexPathForItem(at: CGPoint(x: convertedRect.midX, y: convertedRect.midY)) {
                    let collectionViewIndex = visibleCollectionViewIndexPath.item
                    if collectionViewIndex < cell.imagesData.count {
                        if let cell2 = cell.collectionVW.cellForItem(at: visibleCollectionViewIndexPath) as? FeedBookCVC {
                            if cell.imagesData[collectionViewIndex].video != "" {
                                cell.configureVideoPlayer(view: cell2.videoData, videoURL: URL(string: "\(imageBaseURL)\(cell.imagesData[collectionViewIndex].video ?? "")")!, placeholderImageURL: "\(imageBaseURL)\(cell.imagesData[collectionViewIndex].thumnails ?? "")")
                                cell.playVideo()
                            }
                        }
                    }
                }
            }
            
            print(visibleIndexPath,"indxxxxxxxx")
            for indexPath in tableVW.indexPathsForVisibleRows ?? [] {
                if indexPath != visibleIndexPath {
                    if let cell = tableVW.cellForRow(at: indexPath) as? FeedBookTVC {
                        cell.stopVideo()
                    }
                }
            }
        }
    
    
    
    Collection View Cell 
    
    
     var selectIndex = 0
        var visibleIndex = 0
        var imagesData = [AllFeedsModelFeedsImage]()
        
        var player: AVPlayer?
        var playerLayer: AVPlayerLayer?
        
        override func awakeFromNib() {
            super.awakeFromNib()
            NotificationCenter.default.addObserver(self, selector: #selector(stopvideo), name: NSNotification.Name(rawValue: "stopvideo"), object: nil)
        }
        
        
        @objc func stopvideo(){
            self.stopVideo()
        }
        
        func configureVideoPlayer(view: UIView, videoURL: URL, placeholderImageURL: String) {
    
            player = AVPlayer(url: videoURL)
            playerLayer = AVPlayerLayer(player: player)
            playerLayer?.frame = view.bounds
            playerLayer?.videoGravity = .resizeAspectFill
            view.layer.addSublayer(playerLayer!)
            player?.play()
            NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying(_:)), name: .AVPlayerItemDidPlayToEndTime, object: player?.currentItem)
        }
        
        @objc func playerDidFinishPlaying(_ notification: Notification) {
            player?.seek(to: .zero)
            player?.play()
        }
        
        func playVideo() {
            guard let player = self.player else { return }
            player.play()
        }
        
        func stopVideo() {
            guard let player = self.player else { return }
            player.pause()
        }
        
        func isVisible() -> Bool {
            if self.window == nil {
                return false
            }
            let displayBounds = UIScreen.main.bounds
            let selfFrame = self.convert(self.bounds, to: UIApplication.shared.keyWindow)
            let intersection = displayBounds.intersection(selfFrame)
            let visibility = (intersection.width * intersection.height) / (frame.width * frame.height)
            return visibility >= 0.9
        }
        
    
       func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return imagesData.count
        }
        
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FeedBookCVC", for: indexPath) as! FeedBookCVC
            cell.btnPlay.isHidden = true
            cell.setData(imagesDataa: imagesData[indexPath.item])
            return cell
        }
        
        func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
            let firstVisibleCellIndexPath = collectionVW.indexPathsForVisibleItems.first
            if let firstVisibleCellIndexPath = firstVisibleCellIndexPath {
                visibleIndex = firstVisibleCellIndexPath.item
                collectionVW.reloadItems(at: [firstVisibleCellIndexPath])
            }
        }
        
        func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
            if let cell = cell as? FeedBookCVC{
                if imagesData[indexPath.item].thumnails != "" {
                    if visibleIndex == indexPath.item {
                        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "stopvideo"), object: nil)
                        cell.videoData.isHidden = false
                        if imagesData[indexPath.item].video != "" {
                            configureVideoPlayer(view: cell.videoData, videoURL: URL(string: "\(imageBaseURL)\(imagesData[indexPath.item].video ?? "")")!, placeholderImageURL: "\(imageBaseURL)\(imagesData[indexPath.item].thumnails ?? "")")
                        }
                    }else{
                        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "stopvideo"), object: nil)
                    }
                }else{
                    cell.videoData.isHidden = true
                    player?.pause()
                }
            }
        }