Я проверил демо только видео,
Вот как вы можете достичь it- Создание пользовательского класса Cell, чтобы держать вид видеоплеер, и ручки воспроизведения и паузы способы AVPlayer здесь сам.
Это мой пользовательский класс Cell -
import UIKit
import AVFoundation
class VideoCellTableViewCell: UITableViewCell {
// I have put the avplayer layer on this view
@IBOutlet weak var videoPlayerSuperView: UIView!
var avPlayer: AVPlayer?
var avPlayerLayer: AVPlayerLayer?
var paused: Bool = false
//This will be called everytime a new value is set on the videoplayer item
var videoPlayerItem: AVPlayerItem? = nil {
didSet {
/*
If needed, configure player item here before associating it with a player.
(example: adding outputs, setting text style rules, selecting media options)
*/
avPlayer?.replaceCurrentItem(with: self.videoPlayerItem)
}
}
override func awakeFromNib() {
super.awakeFromNib()
//Setup you avplayer while the cell is created
self.setupMoviePlayer()
}
func setupMoviePlayer(){
self.avPlayer = AVPlayer.init(playerItem: self.videoPlayerItem)
avPlayerLayer = AVPlayerLayer(player: avPlayer)
avPlayerLayer?.videoGravity = AVLayerVideoGravityResizeAspect
avPlayer?.volume = 3
avPlayer?.actionAtItemEnd = .none
// You need to have different variations
// according to the device so as the avplayer fits well
if UIScreen.main.bounds.width == 375 {
let widthRequired = self.frame.size.width - 20
avPlayerLayer?.frame = CGRect.init(x: 0, y: 0, width: widthRequired, height: widthRequired/1.78)
}else if UIScreen.main.bounds.width == 320 {
avPlayerLayer?.frame = CGRect.init(x: 0, y: 0, width: (self.frame.size.height - 120) * 1.78, height: self.frame.size.height - 120)
}else{
let widthRequired = self.frame.size.width
avPlayerLayer?.frame = CGRect.init(x: 0, y: 0, width: widthRequired, height: widthRequired/1.78)
}
self.backgroundColor = .clear
self.videoPlayerSuperView.layer.insertSublayer(avPlayerLayer!, at: 0)
// This notification is fired when the video ends, you can handle it in the method.
NotificationCenter.default.addObserver(self,
selector: #selector(self.playerItemDidReachEnd(notification:)),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: avPlayer?.currentItem)
}
func stopPlayback(){
self.avPlayer?.pause()
}
func startPlayback(){
self.avPlayer?.play()
}
// A notification is fired and seeker is sent to the beginning to loop the video again
func playerItemDidReachEnd(notification: Notification) {
let p: AVPlayerItem = notification.object as! AVPlayerItem
p.seek(to: kCMTimeZero)
}
}
Затем приходит ваш контроллер - Не забудьте, чтобы импортировать AVFoundation
Framework
import UIKit
import AVFoundation
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// The current VisibleIndexPath,
//it can be an array, but for now,
//i am targetting one cell only
//var visibleIP : IndexPath?
var aboutToBecomeInvisibleCell = -1
var avPlayerLayer: AVPlayerLayer!
var videoURLs = Array<URL>()
var firstLoad = true
@IBOutlet weak var feedTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
feedTableView.delegate = self
feedTableView.dataSource = self
//Your model to hold the videos in the video URL
for i in 0..<2{
let url = Bundle.main.url(forResource:"\(i+1)", withExtension: "mp4")
videoURLs.append(url!)
}
// initialized to first indexpath
visibleIP = IndexPath.init(row: 0, section: 0)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 290
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 0
}
Затем укажите свой адрес в cellForRow делегата
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//Thats it, just provide the URL from here, it will change with didSet Method in your custom cell class
let cell = self.feedTableView.dequeueReusableCell(withIdentifier: "videoCell") as! VideoCellTableViewCell
cell.videoPlayerItem = AVPlayerItem.init(url: videoURLs[indexPath.row % 2])
return cell
}
Вся часть видимых ячеек здесь я использовал расчет пересечения всех видимых ячеек здесь,
Найти visible IndexPath
, использовать это для извлечения ячейки пользовательского типа tablecell
. Это также может быть достигнуто с помощью visibleCells
, но я избегал этого, так как вы можете иметь несколько типов ячеек, имеющих изображение, текст или другие материалы.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let indexPaths = self.feedTableView.indexPathsForVisibleRows
var cells = [Any]()
for ip in indexPaths!{
if let videoCell = self.feedTableView.cellForRow(at: ip) as? VideoCellTableViewCell{
cells.append(videoCell)
}
}
let cellCount = cells.count
if cellCount == 0 {return}
if cellCount == 1{
if visibleIP != indexPaths?[0]{
visibleIP = indexPaths?[0]
}
if let videoCell = cells.last! as? VideoCellTableViewCell{
self.playVideoOnTheCell(cell: videoCell, indexPath: (indexPaths?.last)!)
}
}
if cellCount >= 2 {
for i in 0..<cellCount{
let cellRect = self.feedTableView.rectForRow(at: (indexPaths?[i])!)
let intersect = cellRect.intersection(self.feedTableView.bounds)
// curerntHeight is the height of the cell that
// is visible
let currentHeight = intersect.height
print("\n \(currentHeight)")
let cellHeight = (cells[i] as AnyObject).frame.size.height
// 0.95 here denotes how much you want the cell to display
// for it to mark itself as visible,
// .95 denotes 95 percent,
// you can change the values accordingly
if currentHeight > (cellHeight * 0.95){
if visibleIP != indexPaths?[i]{
visibleIP = indexPaths?[i]
print ("visible = \(indexPaths?[i])")
if let videoCell = cells[i] as? VideoCellTableViewCell{
self.playVideoOnTheCell(cell: videoCell, indexPath: (indexPaths?[i])!)
}
}
}
else{
if aboutToBecomeInvisibleCell != indexPaths?[i].row{
aboutToBecomeInvisibleCell = (indexPaths?[i].row)!
if let videoCell = cells[i] as? VideoCellTableViewCell{
self.stopPlayBack(cell: videoCell, indexPath: (indexPaths?[i])!)
}
}
}
}
}
}
Используйте эти методы для воспроизведения.
func playVideoOnTheCell(cell : VideoCellTableViewCell, indexPath : IndexPath){
cell.startPlayback()
}
func stopPlayBack(cell : VideoCellTableViewCell, indexPath : IndexPath){
cell.stopPlayback()
}
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
print("end = \(indexPath)")
if let videoCell = cell as? VideoCellTableViewCell {
videoCell.stopPlayback()
}
}
}
Если интересно, you can check the demo here
это работает, но это действительно Glitchy, когда я пытаюсь делать больше, чем на одну клетку ... и особенно, когда я пытаюсь прокрутки. Любые идеи о том, как это исправить? –
Вам нужно обработать в 'cellForRowAtIndexPath' то, что вам нужно показать. Что именно вам нужно? –
Мне нужно что-то вроде виноградной лозы, где, когда пользователь прокручивает камеру, видео начинает играть. Я думал, что изначально я мог просто показать исходный кадр видео (как изображение), а затем, когда ячейка станет видимой, начните воспроизведение видео. У меня возникли проблемы с выяснением, как это сделать. Есть ли функция tableView, которая позволяет мне проверять visibleRow? –