将视频嵌入UITableViewCell的最佳方法是什么?我正在尝试构建类似Vine/Instagram的东西.
我能够很好地处理异步图像加载SD_WebImage ..但不幸的是它们不支持视频.我也尝试使用MPMoviePlayer进行嵌入,但它只是显示为黑屏.这是我试过的:
override func viewDidLoad() {
super.viewDidLoad()
tableView.frame = CGRectMake(0, 0, view.bounds.width, view.bounds.height);
tableView.delegate = self
tableView.dataSource = self
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.view.addSubview(tableView)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
var moviePlayer : MPMoviePlayerController?
let url = NSURL (string: "http://jplayer.org/video/m4v/Big_Buck_Bunny_Trailer.m4v")
moviePlayer = MPMoviePlayerController(contentURL: url)
if let player = moviePlayer {
player.view.frame = CGRectMake(0, 100, view.bounds.size.width, 180)
player.prepareToPlay()
player.controlStyle = .None
player.repeatMode = .One
player.scalingMode = .AspectFit
cell.addSubview(player.view)
}
return cell
}
Run Code Online (Sandbox Code Playgroud)
Sau*_*dav 16
我只测试了一个视频演示,
以下是如何实现它 - 创建一个自定义Cell类来保存视频播放器视图,并在这里处理avplayer的播放和暂停方法.
这是我的自定义单元类 -
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)
}
}
Run Code Online (Sandbox Code Playgroud)
然后你的控制器 - 别忘了导入AVFoundation
框架
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
}
Run Code Online (Sandbox Code Playgroud)
然后在cellForRow委托中提供您的URL
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
}
Run Code Online (Sandbox Code Playgroud)
这里管理了可见细胞的所有部分,我在这里使用了所有可见细胞的交集计算,
找到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])!)
}
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用这些方法来处理播放.
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()
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果有兴趣,可以在这里查看演示
MPMoviePlayerController
在iOS 9中已弃用,您应该使用AVPlayer
以下方式:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
let videoURL = NSURL(string: "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let player = AVPlayer(URL: videoURL!)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = cell.bounds
cell.layer.addSublayer(playerLayer)
player.play()
return cell
}
Run Code Online (Sandbox Code Playgroud)
您需要包含两个框架:
import AVKit
import AVFoundation
Run Code Online (Sandbox Code Playgroud)
要获取可见单元格/行,UITableView
可以使用两个只读属性:
我希望这对你有帮助.
归档时间: |
|
查看次数: |
10329 次 |
最近记录: |