5

A UICollectionView will consist of a feed of videos. When the user is inline with a video, I would like it to play. With my current setup, several videos play at once (I suppose depending on the pagination) once they are loaded in to the collection view.

How do I play videos inline in a UICollectionView?

A cell in the UICollectionView feed will contain a UIView, which will hold the video player. This is the UIView's class PlayerViewClass:

import Foundation
import UIKit
import AVKit
import AVFoundation

class PlayerViewClass: UIView {

    override static var layerClass: AnyClass {
        return AVPlayerLayer.self
    }

    var playerLayer: AVPlayerLayer {
    
        return layer as! AVPlayerLayer
    }

    var player: AVPlayer? {
        get {
            return playerLayer.player
        }
    
        set {
            playerLayer.player = newValue
        }
    }
}

The Feed's collectionView cellForItemAt indexPath delegate method in the FeedViewController is as follows:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

     let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
        
      if let cell = cell as? MyCollectionViewCell {

      ...

      //Configuring the cell

      ...
    
      //Video player
      let avPlayer = AVPlayer(url: post.fullURL)
        
      //Setting cell's player
      cell.playerView.playerLayer.player = avPlayer
  
      //TODO: Change so this is only executed when the user is inline.
      cell.playerView.player?.play()
    
    }
    return cell
  }

The cell MyCollectionViewCell has an IBOutlet linked to the playerView UIView:

class MyCollectionViewCell {

    @IBOutlet weak var playerView: PlayerViewClass!


override func awakeFromNib() {
    super.awakeFromNib() 

   //Setup, not relevant

   }

}

I found the following GitHub repo, which shows the functionality that I would like to implement; however, I'm a little unsure of how to do this with my setup below.

Thanks so much!

Sergio Charles
  • 379
  • 5
  • 13

2 Answers2

2

You'll need to know which cells are visible.You get that "for free" via the UICollectionView API's visibleCells property. Here's the documentation.

Additionally, you'll need to do some bookkeeping when the UICollectionView scrolls. In reviewing the documentation for UICollectionView, you'll see it is a subclass of UIScrollView. UIScrollView comes with delegate methods that enable you to track this. Here's a "physics for poets" approach to what you could do to accomplish this task:

Let's say this is your view controller:

class YourViewController: UIViewController {
    let collectionView = UICollectionView()

    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.delegate = self
        collectionView.dataSource = self
    }
}

Then, you'd implement your UICollectionViewDelegate and UICollectionViewDataSource methods here:

extension YourViewController: UICollectionViewDelegate, UICollectionViewDataSource {
    // Bare bones implementation
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        // TODO: need to implement
        return 0
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        // TODO: need to implem,ent
        return UICollectionViewCell()
    }
}

Finally, you'd implement UIScrollViewDelegate methods to detect beginning of scrolling and end of scrolling. Here's where you'd implement your logic for starting/stopping video:

extension YourViewController: UIScrollViewDelegate {
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        collectionView.visibleCells.forEach { cell in
            // TODO: write logic to stop the video before it begins scrolling
        }
    }

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        collectionView.visibleCells.forEach { cell in
            // TODO: write logic to start the video after it ends scrolling
        }
    }
}

You'll want to muck around with the timing of stopping/starting animations to see what looks good, so feel free to poke around the various UIScrollViewDelegate methods.

Adrian
  • 16,233
  • 18
  • 112
  • 180
  • Hi Adrian, thank you so much! This is beyond helpful! I have a question: Is there a way to go about determining the video cell that is in the user's current view (or closest to the center of their view) so I can implement the scrollViewDidEndDecelerating and scrollViewWillBeginDragging methods? – Sergio Charles Aug 20 '19 at 04:42
  • Looking around, this seems to answer that: https://stackoverflow.com/questions/34899689/swift-find-out-which-table-view-cell-occupies-most-of-screen – Sergio Charles Aug 20 '19 at 04:47
  • Agreed. However, (I forgot to mention), with my current layout constraints the view container will have at most two cells present at any given time. – Sergio Charles Aug 20 '19 at 04:53
  • 1
    You'd want to compare the center of the visible cells to either the UICollectionView's centers and determine which cell is closest. You'll want to compare CGPoints. – Adrian Aug 20 '19 at 05:31
1

For a play a video in Inline you can refer to the MMPlayerView in gitHub it will be a helpful framework "https://cocoapods.org/pods/MMPlayerView"

Manoj Kumar
  • 121
  • 1
  • 10