AVPlayer.play() in UITableViewCell 暂时阻塞 UI
AVPlayer.play() in UITableViewCell briefly blocks UI
我正在尝试将内联视频添加到我的 UITableViewCells,如 Instagram、Twitter、Vine 等。我正在使用 AVPlayerController 和自定义单元格使用本地视频文件测试 UI(请参阅下面的示例代码)。我等待 AVPlayer 的状态为 ReadyToPlay 然后播放视频。
问题是,当在 tableView 上滚动时,每当加载视频单元格时,UI 会冻结一小部分部分,这使得应用程序显得笨拙。当一行中有多个视频单元时,这种效果会变得更糟。任何想法和帮助将不胜感激
表格视图代码:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("videoCell", forIndexPath: indexPath) as! CustomCell
//Set up video player if cell doesn't already have one
if(cell.videoPlayerController == nil){
cell.videoPlayerController = AVPlayerViewController()
cell.videoPlayerController.view.frame.size.width = cell.mediaView.frame.width
cell.videoPlayerController.view.frame.size.height = cell.mediaView.frame.height
cell.videoPlayerController.view.center = cell.mediaView.center
cell.mediaView.addSubview(cell.videoPlayerController.view)
}
//Remove old observers on cell.videoPlayer if they exist
if(cell.videoObserverSet){
cell.videoPlayer.removeObserver(cell, forKeyPath: "status")
}
let localVideoUrl: NSURL = NSBundle.mainBundle().URLForResource("videoTest", withExtension: "m4v")!
cell.videoPlayer = AVPlayer(URL:localVideoUrl)
cell.videoPlayer.addObserver(cell, forKeyPath:"status", options:NSKeyValueObservingOptions.New, context = nil)
cell.videoObserverSet = true
cell.videoPlayerController.player = cell.videoPlayer
return cell
}
自定义小区观察员代码:
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if(keyPath=="status"){
print("status changed on cell video!");
if(self.videoPlayer.status == AVPlayerStatus.ReadyToPlay){
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.videoPlayer.play()
})
}
}
}
我还尝试使用 loadValuesAsynchronouslyForKeys(["playable"]) 加载视频的 AVAsset 版本,但这对 UI 块也没有帮助。
我怎样才能获得 Instagram 的丝般流畅的视频播放和滚动?
另一个更新
强烈建议使用 Facebook 的异步显示套件 ASVideoNode 作为 AVPlayer 的替代品。在加载和播放视频时,您将获得丝般流畅的 Instagram tableview 性能。我认为 AVPlayer 在主线程上运行了一些进程,并且没有办法绕过它们,因为它发生在一个相对较低的级别。
更新:已解决
我无法直接解决这个问题,但我习惯了一些技巧和假设并获得了我想要的性能。
假设没有办法避免视频在主线程上加载需要一定的时间(除非你是 instagram 并且你拥有一些 AsyncDisplayKit 魔法,但我不想这样做jump), 所以不要尝试移除 UI 块,而是尝试隐藏它。
我通过在我的 tableView
上实现一个简单的 isScrolling 检查来隐藏 UIBlock
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if(self.isScrolling){
if(!decelerate){
self.isScrolling = false
self.tableView.reloadData()
}
}
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if(self.isScrolling){
self.isScrolling = false
self.tableView.reloadData()
}
}
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
self.isScrolling = true
}
然后确保在 tableView 滚动或视频已在播放时不加载视频单元格,并在滚动停止时重新加载 tableView。
if(!isScrolling && cell.videoPlayer == nil){
//Load video cell here
}
但是请务必移除 videoPlayer,并在 videoCell 不再出现在屏幕上时停止收听重播通知。
func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if(tableView.indexPathsForVisibleRows?.indexOf(indexPath) == nil){
if (cell.videoPlayer != nil && murmur.video_url != nil){
if(cell.videoPlayer.rate != 0){
cell.videoPlayer.removeObserver(cell, forKeyPath: "status")
cell.videoPlayer = nil;
cell.videoPlayerController.view.alpha = 0;
}
}
}
}
通过这些更改,我能够在屏幕上一次显示多个 (2) 视频单元格时实现流畅 UI。希望这对您有所帮助,如果您有任何具体问题或我描述的内容不清楚,请告诉我。
我正在尝试将内联视频添加到我的 UITableViewCells,如 Instagram、Twitter、Vine 等。我正在使用 AVPlayerController 和自定义单元格使用本地视频文件测试 UI(请参阅下面的示例代码)。我等待 AVPlayer 的状态为 ReadyToPlay 然后播放视频。
问题是,当在 tableView 上滚动时,每当加载视频单元格时,UI 会冻结一小部分部分,这使得应用程序显得笨拙。当一行中有多个视频单元时,这种效果会变得更糟。任何想法和帮助将不胜感激
表格视图代码:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("videoCell", forIndexPath: indexPath) as! CustomCell
//Set up video player if cell doesn't already have one
if(cell.videoPlayerController == nil){
cell.videoPlayerController = AVPlayerViewController()
cell.videoPlayerController.view.frame.size.width = cell.mediaView.frame.width
cell.videoPlayerController.view.frame.size.height = cell.mediaView.frame.height
cell.videoPlayerController.view.center = cell.mediaView.center
cell.mediaView.addSubview(cell.videoPlayerController.view)
}
//Remove old observers on cell.videoPlayer if they exist
if(cell.videoObserverSet){
cell.videoPlayer.removeObserver(cell, forKeyPath: "status")
}
let localVideoUrl: NSURL = NSBundle.mainBundle().URLForResource("videoTest", withExtension: "m4v")!
cell.videoPlayer = AVPlayer(URL:localVideoUrl)
cell.videoPlayer.addObserver(cell, forKeyPath:"status", options:NSKeyValueObservingOptions.New, context = nil)
cell.videoObserverSet = true
cell.videoPlayerController.player = cell.videoPlayer
return cell
}
自定义小区观察员代码:
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if(keyPath=="status"){
print("status changed on cell video!");
if(self.videoPlayer.status == AVPlayerStatus.ReadyToPlay){
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.videoPlayer.play()
})
}
}
}
我还尝试使用 loadValuesAsynchronouslyForKeys(["playable"]) 加载视频的 AVAsset 版本,但这对 UI 块也没有帮助。
我怎样才能获得 Instagram 的丝般流畅的视频播放和滚动?
另一个更新 强烈建议使用 Facebook 的异步显示套件 ASVideoNode 作为 AVPlayer 的替代品。在加载和播放视频时,您将获得丝般流畅的 Instagram tableview 性能。我认为 AVPlayer 在主线程上运行了一些进程,并且没有办法绕过它们,因为它发生在一个相对较低的级别。
更新:已解决
我无法直接解决这个问题,但我习惯了一些技巧和假设并获得了我想要的性能。
假设没有办法避免视频在主线程上加载需要一定的时间(除非你是 instagram 并且你拥有一些 AsyncDisplayKit 魔法,但我不想这样做jump), 所以不要尝试移除 UI 块,而是尝试隐藏它。
我通过在我的 tableView
上实现一个简单的 isScrolling 检查来隐藏 UIBlockfunc scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if(self.isScrolling){
if(!decelerate){
self.isScrolling = false
self.tableView.reloadData()
}
}
}
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if(self.isScrolling){
self.isScrolling = false
self.tableView.reloadData()
}
}
func scrollViewWillBeginDragging(scrollView: UIScrollView) {
self.isScrolling = true
}
然后确保在 tableView 滚动或视频已在播放时不加载视频单元格,并在滚动停止时重新加载 tableView。
if(!isScrolling && cell.videoPlayer == nil){
//Load video cell here
}
但是请务必移除 videoPlayer,并在 videoCell 不再出现在屏幕上时停止收听重播通知。
func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if(tableView.indexPathsForVisibleRows?.indexOf(indexPath) == nil){
if (cell.videoPlayer != nil && murmur.video_url != nil){
if(cell.videoPlayer.rate != 0){
cell.videoPlayer.removeObserver(cell, forKeyPath: "status")
cell.videoPlayer = nil;
cell.videoPlayerController.view.alpha = 0;
}
}
}
}
通过这些更改,我能够在屏幕上一次显示多个 (2) 视频单元格时实现流畅 UI。希望这对您有所帮助,如果您有任何具体问题或我描述的内容不清楚,请告诉我。