概述
最近應專案需求,實現在 tableView中新增視訊自動播放功能,產品功能類似與微博的視訊資訊流播放樣式,為此實現了好一段時間,現在把當初實現的方法以及內容記錄於此,以便後續回顧以及檢視。
思路
視訊螢幕居中播放
因為之前沒有做過這樣的功能,所以也是做了不少調研工作,因為微博的視訊很具有代表性,所以以此為研究物件,構思了一下相關的播放邏輯內容。
注意到微博視訊播放是居中位置播放,也就是說距離中心位置最近的視訊播放 cell 進行自動播放,而其他 cell 中的視訊處於停止狀態,顯然這是一個螢幕居中選定視訊的一個演算法,而這個演算法也這是控制視訊播放的核心內容。為此實現它也有了相應的思路,而這塊內容大致可以分為三個步驟:
- 找出當前螢幕中已經正在顯示的 cell,用陣列存起來
- 在陣列中找出距離螢幕中央最近的 cell
- 儲存第二個步驟中找出的 cell(牽扯到後續播放以及停止)
使用單例進行視訊的有序播放
仔細看了一下微博的視訊播放,會發現資訊流中的視訊始終都是一個視訊在播放,無論怎麼滑動,都是一個視訊在當前播放,我想這麼做無疑也是兩點,一是保證視訊播放的唯一性,二則是減少記憶體的佔用。如果每個 cell 中都新增一個視訊播放器的話,也會佔用不少記憶體吧。還有一點就是,如果設計成單例進行視訊播放的話,整個資訊流中視訊播放體系就會變得很好控制,邏輯也會變得愈發清晰。所以這種情況下的視訊播放設計成單例播放無疑是最好的選擇。
控制滾動判斷視訊播放的時機
因為要不斷的找出在螢幕中顯示的 cell,以及要比較出當前離螢幕中最近的視訊cell,所以這個過程如果放在 tableView 中的 didScrollview 方法中判斷的話,會在滑動的時候瘋狂比較查詢,這樣做顯然是不好的。所以滾動過程中我們儘量不去判斷這些邏輯,在滾動停止的時候再去觸發判斷的邏輯,這樣既能夠滿足自動播放的功能,也省去了來回比較的邏輯過程。所以我們可以在 tableview 的scrollViewDidEndDragging
與scrollViewDidEndDecelerating
回撥中進行判斷。
實現
有了思路,接下來就是實現了,其實實現方式多種多樣,重在思想。
視訊螢幕居中播放
該功能的實現實際上主要在於找到當前螢幕中距離螢幕中線距離最近的 cell,然後選中 cell,讓其進行播放也就達到了播放的目的,程式碼如下:
/* 進行視訊自動播放判定邏輯判斷 */
- (void)handleScrollPlay{
LCVideoCell *cell = (LCVideoCell *)[self getMinCenterCell];
if (cell && ![self.playingCell isEqual:cell]) {
NSLog(@"當前的 cell 存在,是%ld",cell.tag);
cell.backgroundColor = [UIColor redColor];
if (self.playingCell) {
LCVideoCell *playingCell = (LCVideoCell *)self.playingCell;
playingCell.backgroundColor = [UIColor whiteColor];
}
self.playingCell = cell;
}
}
/* 獲取距離螢幕最中間的cell */
- (id)getMinCenterCell{
CGFloat minDelta = CGFLOAT_MAX;
//螢幕中央位置
CGFloat screenCenterY = SCREEN_HEIGHT * 0.5;
//當前距離螢幕中央最近的cell
id minCell = nil;
for (id cell in self.visibleCells) {
if ([cell isKindOfClass:[LCVideoCell class]]) {
LCVideoCell *videoCell = (LCVideoCell *)cell;
//獲取當前 cell 的居中點座標
CGPoint cellCenterPoint = CGPointMake(videoCell.frame.origin.x, videoCell.frame.size.height * 0.5 + videoCell.frame.origin.y);
//轉換當前的 cell 的座標
CGPoint coorPoint = [videoCell.superview convertPoint:cellCenterPoint toView:nil];
CGFloat deltaTemp = fabs(coorPoint.y - screenCenterY);
if (deltaTemp < minDelta) {
minCell = videoCell;
minDelta = deltaTemp;
}
}
}
return minCell;
}
複製程式碼
判斷當前的播放的 cell 是否已經移動到螢幕外面
這個判斷邏輯主要是實現在移出到螢幕外之後,視訊應該停止的功能,所以為此我們需要寫一個方法去判斷當前播放的 cell 的可見性。以及在滾動圖中實時判斷當前的播放的cell是否已經移動到螢幕外面。判斷的程式碼如下:
/* 當前播放的視訊是否劃出螢幕 */
- (BOOL)playingCellIsOutScreen{
if (!self.playingCell) {
return YES;
}
LCVideoCell *videoCell = (LCVideoCell *)self.playingCell;
//當前顯示區域內容
CGRect visiableContentZone = [UIScreen mainScreen].bounds;
//向上滾動
if(self.scrollDirection == LC_SCROLL_UP){
//找到滾動時候的正在播放視訊的cell底部的y座標點,計算出當前播放的視訊是否移除到螢幕外
CGRect playingCellFrame = videoCell.frame;
//當前正在播放視訊的座標
CGPoint cellBottomPoint = CGPointMake(playingCellFrame.origin.x, playingCellFrame.size.height + playingCellFrame.origin.y);
//座標系轉換(轉換到 window座標)
CGPoint coorPoint = [videoCell.superview convertPoint:cellBottomPoint toView:nil];
return CGRectContainsPoint(visiableContentZone, coorPoint);
}
//向下滾動
else if(self.scrollDirection == LC_SCROLL_DOWN){
//找到滾動時候的正在播放視訊的cell底部的y座標點,計算出當前播放的視訊是否移除到螢幕外
CGRect playingCellFrame = videoCell.frame;
//當前正在播放視訊的座標
CGPoint orginPoint = CGPointMake(playingCellFrame.origin.x, playingCellFrame.origin.y);
//座標系轉換(轉換到 window座標)
CGPoint coorPoint = [videoCell.superview convertPoint:orginPoint toView:nil];
return CGRectContainsPoint(visiableContentZone, coorPoint);
}
else{
return NO;
}
return YES;
}
複製程式碼
效果
視訊自動選擇播放的效果如下所示
總結
視訊的居中播放思想就是這樣,當然播放器以及網路的判斷應該是播放器播放內部的處理方案了,希望能夠給正在開發或者想要開發視訊自動選擇播放的同學們一點小小的啟發。