我沒有參照目前簡書上最流行的方法:scrollView直接加載3個(gè)播放器界面的做法坏匪;因?yàn)楫?dāng)時(shí)做這個(gè)功能的時(shí)候,就直接開擼了撬统;
我的視頻輪播直接用UITableView實(shí)現(xiàn)的适滓,通過緩存indexPath和cell來做當(dāng)前視頻的標(biāo)記。
首先恋追,tableView要開啟分頁模式: tableView.pageEnable = YES凭迹。
- UIViewController中定義下面屬性(在tableView滾動(dòng)過程中,緩存這些屬性):
// 當(dāng)前播放的索引
@property (nonatomic, strong) NSIndexPath* curPlayIndexPath;
// 當(dāng)前播放的cell(跟上面curPlayIndexPath是一一對應(yīng)的)
@property (nonatomic, weak) JFVideoCell* curPlayingCell; // 封裝了視頻播放控件和方法: play|pause
在curPlayIndexPath
的setter:
中更新curPlayingCell
:
- (void)setCurPlayIndexPath:(NSIndexPath *)curPlayIndexPath {
if ([_curPlayingCell isEqual:curPlayIndexPath]) {
return;
}
_curPlayIndexPath = curPlayIndexPath;
JFVideoCell* cell = [self.tableView cellForRowAtIndexPath:_curPlayIndexPath];
// 如果cell不存在苦囱,說明是第一個(gè)cell,還沒入棧到tableView的重用隊(duì)列嗅绸,這里獲取不到的;在cellForRowAtIndexPath回調(diào)中緩存這個(gè)cell
if (cell) {
self.curPlayingCell = cell;
}
}
在 curPlayingCell
的setter:
中控制視頻的播放和暫停:
- (void)setCurPlayingCell:(JFVideoCell *)curPlayingCell {
// 不要重復(fù)設(shè)置
if (_curPlayingCell && _curPlayingCell == curPlayingCell) {
return;
}
// 當(dāng)前播放的cell存在時(shí),暫停播放
if (_curPlayingCell) {
[_curPlayingCell pause];
}
// 更新cell
_curPlayingCell = curPlayingCell;
// 播放新緩存的cell
if (_curPlayingCell) {
[_curPlayingCell playVideo];
}
}
好了撕彤,前置條件已準(zhǔn)備好;下面開始分析tableView的滾動(dòng)回調(diào)情況:
· tableView正秤沭滑動(dòng),會(huì)觸發(fā)scrollViewDidScroll
回調(diào)羹铅,停止?jié)L動(dòng)時(shí)會(huì)觸發(fā) scrollViewDidEndDecelerating
回調(diào)蚀狰;
· 點(diǎn)擊屏幕狀態(tài)欄時(shí),只觸發(fā)scrollViewDidScroll
职员,不會(huì)在停止?jié)L動(dòng)時(shí)觸發(fā) scrollViewDidEndDecelerating
回調(diào)麻蹋;
· tableView初始加載完畢時(shí),既不觸發(fā)scrollViewDidScroll
回調(diào)焊切,也不觸發(fā) scrollViewDidEndDecelerating
回調(diào)扮授,只觸發(fā)tableView: cellForRowAtIndexPath:
回調(diào);
那么专肪,對上面3種情況刹勃,分別進(jìn)行分析。
- tableView正澈坑龋滑動(dòng)時(shí):
正成詈唬滑動(dòng),tableView 會(huì)觸發(fā)回調(diào):scrollViewDidEndDecelerating:
,在這個(gè)回調(diào)中诺苹,計(jì)算當(dāng)前 cell 的 indexPath咕晋。
// 當(dāng)前cell的行數(shù)
NSInteger row = (NSInteger)scrollView.contentOffset.y / SCREEN_HEIGHT;
self.curPlayIndexPath = [NSIndexPath indexPathForRow:row inSection:0];
這個(gè)cell和indexPath都會(huì)被緩存下來,視頻也會(huì)被播放收奔;
- 只觸發(fā)
scrollViewDidScroll
掌呜,而不觸發(fā)scrollViewDidEndDecelerating
的情況:
點(diǎn)擊了屏幕狀態(tài)欄,tableView滑動(dòng)到頂部坪哄。
這個(gè)時(shí)候质蕉,self.curPlayIndexPath
就只能在scrollViewDidScroll
的回調(diào)中設(shè)置了:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint velocity = [scrollView.panGestureRecognizer velocityInView:self.view];
// 當(dāng)前所有的視頻個(gè)數(shù)
NSInteger total = [self.vmData numberOfRowsInSection:0];
CGFloat contentOffsetY = scrollView.contentOffset.y;
NSInteger row = self.curPlayIndexPath ? self.curPlayIndexPath.row : 0;
CGFloat curCellStartY = row * JFSCREEN_HEIGHT;
// 在最后一個(gè)cell的位置
if (total > 0 && row == total - 1) {
// 不是上拉刷新
if (velocity.y > 0) {
scrollView.pagingEnabled = YES;
}
// 上拉刷新時(shí):要屏蔽分頁效果势篡,否則MJRefresh懸停會(huì)導(dǎo)致cell位置不在屏幕邊界
else if (velocity.y < 0) {
scrollView.pagingEnabled = NO;
}
}
// 一種情況:scrollViewDidEndDecelerating沒有觸發(fā)時(shí),且當(dāng)前滾動(dòng)到了頂部模暗,重置當(dāng)前播放indexPath為0位置
if (contentOffsetY == 0 && !scrollView.isTracking) {
self.curPlayIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
return;
}
// 當(dāng)前播放的cell的indexPath不在屏幕可見區(qū)內(nèi)禁悠,就要設(shè)置indexPath為空,將當(dāng)前播放暫停
if (contentOffsetY <= curCellStartY - JFSCREEN_HEIGHT || contentOffsetY >= curCellStartY + JFSCREEN_HEIGHT) {
if (self.curPlayIndexPath) {
self.curPlayIndexPath = nil;
}
}
// 而cell能到屏幕可見區(qū)內(nèi)的話兑宇,scrollViewDidEndDecelerating就一定會(huì)被觸發(fā)碍侦,到那個(gè)方法里面去重置當(dāng)前播放的indexPath
}
- 既不觸發(fā)
scrollViewDidScroll
,也不觸發(fā)scrollViewDidEndDecelerating
的情況:
tableView初始狀態(tài)隶糕;這時(shí)只有在tableView: cellForRowAtIndexPath:
回調(diào)中緩存indexPath了;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
JFVideoCell* cell = [tableView dequeueReusableCellWithIdentifier:@"JFVideoCell"];
// 設(shè)置視頻數(shù)據(jù)模型
cell.model = [self.vmData modelForRowAtIndexPath:indexPath];
CGFloat contentOffsetY = tableView.contentOffset.y;
CGFloat headerHeight = tableView.mj_header.height;
f // 這種情況為:界面和數(shù)據(jù)剛加載完畢瓷产,不會(huì)觸發(fā)任何滾動(dòng)事件
if (indexPath.row == 0 && contentOffsetY > -0.01 - headerHeight && contentOffsetY < 0.01 + headerHeight) {
// row==0時(shí),因?yàn)閏ell還沒入棧枚驻,cellForRowAtIndexPath:獲取不到cell濒旦;不能自動(dòng)播放,這里要手動(dòng)
self.curPlayIndexPath = indexPath;
self.curPlayingCell = cell;
}
return cell;
}
- 到這里再登,基本的滑動(dòng)播放視頻就實(shí)現(xiàn)了尔邓。但是,還有個(gè)情況:
從本界面跳轉(zhuǎn)到別的界面時(shí)锉矢,需要暫停當(dāng)前的播放梯嗽;然后,又從別的界面回到本界面時(shí)沈撞,要恢復(fù)當(dāng)前播放慷荔。
這個(gè) 當(dāng)前 雕什, 就是緩存的curPlayingCell
屬性缠俺。
既然這樣,方法就簡單了:
// 轉(zhuǎn)場時(shí):暫停當(dāng)前播放
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// 暫停當(dāng)前的播放
if (self.curPlayingCell) {
[self.curPlayingCell pause];
}
}
// 回場時(shí):繼續(xù)當(dāng)前播放
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// 繼續(xù)當(dāng)前的播放
if (self.curPlayingCell) {
[self.curPlayingCell playVideo];
}
}
實(shí)現(xiàn)完畢贷岸!
我們的APP即將上線了壹士,期待下載鏈接!