iOS-仿抖音視頻輪播

我沒有參照目前簡書上最流行的方法: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

curPlayIndexPathsetter:中更新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;
    }
}

curPlayingCellsetter:中控制視頻的播放和暫停:

- (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即將上線了壹士,期待下載鏈接!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末偿警,一起剝皮案震驚了整個(gè)濱河市躏救,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌螟蒸,老刑警劉巖盒使,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異七嫌,居然都是意外死亡少办,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門诵原,熙熙樓的掌柜王于貴愁眉苦臉地迎上來英妓,“玉大人挽放,你說我怎么就攤上這事÷溃” “怎么了辑畦?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長腿倚。 經(jīng)常有香客問我纯出,道長,這世上最難降的妖魔是什么猴誊? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任潦刃,我火速辦了婚禮,結(jié)果婚禮上懈叹,老公的妹妹穿的比我還像新娘乖杠。我一直安慰自己,他們只是感情好澄成,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布胧洒。 她就那樣靜靜地躺著,像睡著了一般墨状。 火紅的嫁衣襯著肌膚如雪卫漫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天肾砂,我揣著相機(jī)與錄音列赎,去河邊找鬼。 笑死镐确,一個(gè)胖子當(dāng)著我的面吹牛包吝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播源葫,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼诗越,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了息堂?” 一聲冷哼從身側(cè)響起嚷狞,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎荣堰,沒想到半個(gè)月后床未,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡振坚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年薇搁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屡拨。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡只酥,死狀恐怖褥实,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情裂允,我是刑警寧澤损离,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站绝编,受9級特大地震影響僻澎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜十饥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一窟勃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧逗堵,春花似錦秉氧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至作媚,卻和暖如春攘滩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背纸泡。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工漂问, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人女揭。 一個(gè)月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓蚤假,卻偏偏與公主長得像,于是被迫代替她去往敵國和親田绑。 傳聞我的和親對象是個(gè)殘疾皇子勤哗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,089評論 1 32
  • 標(biāo)題上的這兩個(gè)詞抡爹,相信各位看官也時(shí)逞谇可以聽到,使用人群一般集中在筆者的上一代人冬竟;能夠?qū)⑦@兩個(gè)矛盾的詞匯有機(jī)的整合在...
    拜金主義異形閱讀 731評論 5 12
  • 【1】當(dāng)能獲取到當(dāng)前的響應(yīng)者是UIView的時(shí)候欧穴,可以通過響應(yīng)者鏈一層一層往上找。 【2】當(dāng)不知道當(dāng)前響應(yīng)者的情況...
    努力奮斗的絕望者閱讀 394評論 0 1
  • 計(jì)算機(jī)學(xué)院“銅興社區(qū)”志愿活動(dòng)圓滿成功 (冰花通訊社記者苗子建)2017年12月21日下午泵殴,2017級計(jì)算機(jī)170...
    東北大學(xué)2018閱讀 218評論 0 0