OC-抖音上拉加載(你以為單純用MJRefresh就能實現(xiàn)耙饰?那你就錯了)

2018-8-16修改:
根據(jù)@劉奇林同學(xué)的疑問罪裹,pageebable和mjfooter沒有沖突,所以我再次測試了我的代碼孵延。

將scrollViewDidScroll里面關(guān)閉pageebable注釋掉吕漂,測試后發(fā)現(xiàn)mjfooter顯示正常(此時重設(shè)_tableView.contentOffset的代碼還在)。

于是我就想是不是pageebable和mjfooter真的沒有沖突隙袁,如果沒有沖突的話那那些判斷上拉還是下拉痰娱,以及重設(shè)_tableView.contentOffset的代碼是不是都沒有用了呢弃榨?

我就將_tableView.contentOffset的代碼也注釋掉菩收,滑動發(fā)現(xiàn)頁面不正常了,第一次上拉加載的時候mjfooter能正常顯示鲸睛,第二次加載娜饵,觸發(fā)mj后頁面就回彈了,并且加載成功后頁面下移了44像素官辈。

到底是哪兒出了問題呢箱舞?明明注掉pageebable開關(guān)的代碼時是沒問題的呀?看來還是需要設(shè)置_tableView.contentOffset拳亿。

我將加載成功后重置_tableView.contentOffset的代碼解開晴股,加載成功后頁面不再下移,但footer依然顯示不正常肺魁,我又將scrollViewWillBeginDecelerating中設(shè)置contentOffset的代碼解開电湘,依然不好使,后來發(fā)現(xiàn)scrollViewWillBeginDecelerating中的代碼只有在_tableView.updating=yes的時候才會走(???♀????♀????♀????♀?)鹅经,于是又解開了scrollViewDidScroll中的代碼寂呛,一切都正常了。

但我又發(fā)現(xiàn)了另一個問題瘾晃,當(dāng)正在上拉加載時贷痪,用戶又下滑列表了,雖然頁面還是page的方式滑動蹦误,但是會錯位劫拢,因為在拿到返回數(shù)據(jù)之前_tableView.updating一直是yes,也就是一直會執(zhí)行scrollViewWillBeginDecelerating中將頁面上移44像素的代碼强胰。

那是不是可以加個判斷舱沧,只有上拉加載時將頁面上移,上拉加載沒拿到返回值時用戶下拉就不將頁面上移哪廓,就正常顯示即可狗唉。最后將scrollViewDidScroll中判斷上拉還是下拉的代碼挪到scrollViewWillBeginDecelerating中,當(dāng)上拉觸發(fā)mj時頁面上移涡真,頁面下拉時不做任何操作即可分俯。大功告成

感謝@劉奇林同學(xué)的質(zhì)疑肾筐,讓我省去了控制pageebable開關(guān)的一系列代碼,稍微精簡了一下代碼?? 這種質(zhì)疑和求真的心態(tài)很棒哦??????????????????

代碼修改如下:

先上DEMO記得star哦

效果圖

之前實現(xiàn)了抖音下拉刷新效果之后就沒再繼續(xù)研究缸剪,想著上拉加載隨便集成一下MJRefresh就可以了吗铐,很簡單嘛,等需要的時候再加進去就好了杏节。
直到某一天有個小伙伴跟我說添加上拉加載有問題唬渗,我就不信了,怎么可能呢奋渔,自己試了試還真是不少坑镊逝。

現(xiàn)在想來之前真的是圖樣圖森破,你以為你以為的就是你以為的嫉鲸?實踐出真知撑蒜,萬事都不能想當(dāng)然,只有自己真的去操作了才能明白玄渗。

下面咱們來一起實現(xiàn)一下:
看之前先熟悉一下OC-仿抖音下拉刷新,操作是基于之前的demo的

1座菠、添加上拉加載-使用延時模擬請求
self.tableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [weakSelf getMoreData];
        });
        
    }];
加上mj_footer之后運行起來,發(fā)現(xiàn)根本觸發(fā)不了mj藤树,因為之前代碼里默認(rèn)關(guān)閉了tableView的bounces浴滴,滑到最后不打開彈性效果是沒辦法往上拖拽觸發(fā)mj。

一開始的想法是判斷當(dāng)前是否播放到列表的最后一個cell岁钓,如果是就打開升略,不是就關(guān)閉。后來想想其實只有第一個cell的時候才需要關(guān)閉彈性效果甜紫,就改成了下面代碼:

//此方法每次cell播放的時候都會掉用降宅,所以寫在了這里,實時判斷
- (void)tableView:(UITableView *)tableView willPlayVideoOnCell:(UITableViewCell *)cell {
    VideoTableViewCell *Cell = (VideoTableViewCell *)cell;
    Cell.playButton.selected = NO;
    playIndex = (int)Cell.playButton.tag;
    [cell.jp_videoPlayView jp_resumeMutePlayWithURL:cell.jp_videoURL
                                 bufferingIndicator:nil
                                       progressView:nil
                            configurationCompletion:^(UIView * _Nonnull view, JPVideoPlayerModel * _Nonnull playerModel) {
                                view.jp_muted = NO;
                            }];
    if (Cell.playButton.tag==0) {
        //列表第一個cell時關(guān)閉
        self.tableView.bounces = NO;
    }else
        self.tableView.bounces = YES;
}
2囚霸、pagingEnabled和mj的矛盾

按照第一步腰根,調(diào)整bounces的開關(guān)后,確實能夠觸發(fā)mj了拓型,但是由于pagingEnabled的回彈效果额嘿,每次上拉觸發(fā)mj后頁面又回滾回去,沒有正常上拉加載時footer懸停然后轉(zhuǎn)圈的效果劣挫,導(dǎo)致用戶根本看不見mj的加載狀態(tài)册养,并且加載完成后reloadData,cell的位置會錯亂压固,不是剛好整屏整屏的顯示球拦,有偏移。

1)先解決下回滾的問題

既然pagingEnabled影響了加載效果的顯示,那是不是也可以通過手段來控制pagingEnabled的開關(guān)呢坎炼?

于是我開始監(jiān)控tableView的滑動愧膀,通過playIndex記錄當(dāng)前播放到第幾個cell,當(dāng)播放到最后一個cell,用戶又繼續(xù)上滑說明用戶正在上拉加載谣光,此時是關(guān)閉pagingEnabled的最佳時機檩淋,具體代碼如下,有注釋:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    [self.tableView jp_scrollViewDidScroll];
    int index= (int)self.tableView.contentOffset.y/kHeight;
    //scroll是與整屏相比的偏移量萄金,肯定是正的
    float scroll = self.tableView.contentOffset.y- index*kHeight;
    //與上一個滑動點比較蟀悦,區(qū)分上滑還是下滑
    float offset = self.tableView.contentOffset.y- oldOffset.y;
    //記錄當(dāng)前tableView.contentOffset
    oldOffset = self.tableView.contentOffset;
    if (offset>0) {
        //上拉-44是mj_footer的高度,當(dāng)拖拽超過44的時候會觸發(fā)mj
        if (playIndex==_tableView.items.count-1&&scroll>44) {
            if (_updating==NO) {
                //判斷是否正在刷新氧敢,正在刷新就不再進行如下設(shè)置日戈,以免重復(fù)加載
                _updating = YES;
                //進到這里說明用戶正在上拉加載,觸發(fā)mj,此時要關(guān)閉翻頁功能否則頁面回彈mj_footer就看不到了福稳,setContentOffset也無效
                self.tableView.pagingEnabled = NO;
                //給tableView設(shè)置一個固定的Offset涎拉,往上偏移點,將footer展示出來的圆,要大于44才會觸發(fā)footer
                [self.tableView setContentOffset:CGPointMake(0, index*kHeight+50) animated:NO];
                [self.tableView.mj_footer beginRefreshing];
            } 
        }
    }
}

然后在加載結(jié)束后再打開pagingEnabled即可,這樣就能看到mj的加載狀態(tài)了半火,抖音加載結(jié)束后會自動滾動到下一個cell播放越妈,所以我也做了此操作,但是自動滾動后就會發(fā)現(xiàn)當(dāng)前cell總是向上偏移了一部分钮糖,露出當(dāng)前cell的下一個cell,如圖:
紅框內(nèi)偏移高度
2)解決偏移問題

我打印了cell自動滾動后self.tableView.contentOffset.y梅掠,與整屏偏移量是44,也就是說頁面剛好上移了44像素店归,那不就是footer的高度嗎阎抒?于是我在自動滾動后讓tableView.contentOffset.y再下移44,矯正過來消痛,發(fā)現(xiàn)好使且叁,代碼如下:

-(void)getMoreData
{
    _updating=NO;
    [self.tableView.mj_footer endRefreshing];
    int index = (int)self.pathStrings.count;
    [self.pathStrings addObjectsFromArray:@[@"http://p11s9kqxf.bkt.clouddn.com/coder.mp4",@"http://p11s9kqxf.bkt.clouddn.com/cat.mp4",@"http://p11s9kqxf.bkt.clouddn.com/coder.mp4",@"http://p11s9kqxf.bkt.clouddn.com/cat.mp4"]];
    [self.tableView reloadData];
    //滾動到下一個cell
    [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:NO];
    NSLog(@"1w:%.f",self.tableView.contentOffset.y);
    //mjfooter高度是44,上拉加載時頁面會向上偏移44像素秩伞,數(shù)據(jù)加載完畢后需要將contentOffset復(fù)位
    self.tableView.contentOffset =CGPointMake(0, self.tableView.contentOffset.y-44);
    NSLog(@"%.f",self.tableView.contentOffset.y);
    //讓cell開始播放
    VideoTableViewCell *cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0]];
    [self tableView:self.tableView willPlayVideoOnCell:cell];
    //刷新結(jié)束逞带,開啟翻頁功能
    self.tableView.pagingEnabled = YES;
}
3、ios11適配問題

根據(jù)上面纱新,小偏移問題解決了展氓,可是我繼續(xù)再上滑查看后面cell的時候,詭異的事情發(fā)生了脸爱,后面的偏移更大了遇汞,而且滑動到底部就再也拽不動了:
紅框內(nèi)偏移部分有點大
這就有點傻眼了,這偏移的過分了點,我輕輕滑動頁面空入,打印tableView減速后contentOffset.y的數(shù)值教寂,發(fā)現(xiàn)數(shù)值沒問題,剛好是屏幕高度的整數(shù)倍执庐,一點都沒偏移酪耕。

這是什么情況?翻頁效果轨淌、回彈效果都沒問題迂烁,contentOffset.y也對著呢,就是cell顯示的不正常递鹉,難道是pagingEnabled在反復(fù)開關(guān)盟步、設(shè)置contentOffset.y之后有點神經(jīng)錯亂了?

于是我嘗試了各種辦法躏结,徹底關(guān)閉pagingEnabled正橙磁蹋滑動cell、修改cell的高度不讓它全屏在進行測試媳拴、通過監(jiān)控滑動過程自己模擬翻頁效果黄橘、翻看老項目非全屏cell滑動加載效果……所有測試失敗后我又回退到一開始的樣子

啊啊啊啊,總之我折騰了一天屈溉,感覺要瘋的節(jié)奏塞关,眼看快下班了,要不真機試試吧子巾,說不定是模擬器有問題呢帆赢?(當(dāng)時我的手機是11.3,剛升級线梗,xcode是9.2不支持椰于,升級xcode太費時間了,所以一直在用模擬器測試)

從同事那借了個低版本的手機仪搔,10.3的瘾婿,運行后,完美僻造,拖拽憋他,刷新,加載髓削,復(fù)位一點問題都沒有竹挡,很順暢。(此時的我心中一萬個草泥馬奔騰而過……模擬器的鍋立膛,讓我浪費了一天)

沒問題了揪罕,就開心的下班了梯码。

第二天到了公司,想著要不給xcode升個級吧好啰,總借手機用怪麻煩的轩娶,然后是漫長的等待升級。升級結(jié)束后框往,把程序在我手機上運行了一下鳄抒,發(fā)現(xiàn)昨天的詭異問題又出現(xiàn)了。就隔了一個晚上椰弊,怎么就不好使了许溅?誰動我代碼了?

又跑去同事那借了手機運行秉版,沒問題贤重,在我手機上再次運行,有問題清焕。同樣的代碼并蝗,設(shè)備一樣,效果卻不一樣秸妥。唯一的差異在于系統(tǒng)滚停,我是11.3,他是10.3筛峭。等等铐刘,難道是ios11的適配沒做好?

翻了翻代碼影晓,果然沒適配,于是把之前適配ios11的代碼搬過來檩禾,一運行挂签,徹底沒問題了。

        self.estimatedRowHeight = 0;
        self.estimatedSectionHeaderHeight = 0;
        self.estimatedSectionFooterHeight = 0;
        //適配ios11自適應(yīng)上導(dǎo)航 安全區(qū)域
        self.separatorStyle = UITableViewCellSeparatorStyleNone;
        SEL selector = NSSelectorFromString(@"setContentInsetAdjustmentBehavior:");
        if ([self respondsToSelector:selector]) {
            IMP imp = [self methodForSelector:selector];
            void (*func)(id, SEL, NSInteger) = (void *)imp;
            func(self, selector, 2);
            
        }

適配ios11的代碼有那么多行盼产,其實有效果的是estimatedRowHeight這個饵婆。具體請參考鏈接:關(guān)于iOS11中estimatedRowHeight看完你就明白了

4、細節(jié)整理

確定沒問題了之后戏售,我將代碼整理了一番侨核,整理好之后又測試了一遍,將延時時間調(diào)大了觀察效果灌灾,當(dāng)頁面停留在加載狀態(tài)的時候我手指下滑了一下搓译,發(fā)現(xiàn)沒有翻頁回彈的效果了,一下子下滑了好幾個cell锋喜。

哦些己,對了豌鸡,我在加載的時候關(guān)閉了pagingEnabled,得在加載結(jié)束后才會打開段标,可是此時如果用戶像我一樣下滑了不就露餡了了么涯冠?本著求知心態(tài),我將手機設(shè)置為3G網(wǎng)絡(luò)逼庞,快速滑動抖音首頁蛇更,出現(xiàn)加載后,我又下滑觀察赛糟,抖音是有翻頁效果的派任。摸清套路后我開始思考我該怎么做?

審查代碼后發(fā)現(xiàn)scrollViewDidScroll中我只判斷了用戶上拉虑灰,沒有處理下滑吨瞎,那就再加上下滑判斷。
整理后代碼如下

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    [self.tableView jp_scrollViewDidScroll];
    int index= (int)self.tableView.contentOffset.y/kHeight;
    //scroll是與整屏相比的偏移量穆咐,肯定是正的
    float scroll = self.tableView.contentOffset.y- index*kHeight;
    //與上一個滑動點比較颤诀,區(qū)分上滑還是下滑
    float offset = self.tableView.contentOffset.y- oldOffset.y;
    //記錄當(dāng)前tableView.contentOffset
    oldOffset = self.tableView.contentOffset;
    if (offset>0) {
        //上拉-44是mj_footer的高度,當(dāng)拖拽超過44的時候會觸發(fā)mj
        if (playIndex==_tableView.items.count-1&&scroll>44) {
            if (_tableView.updating==NO) {
                //判斷是否正在刷新对湃,正在刷新就不再進行如下設(shè)置崖叫,以免重復(fù)加載
                _tableView.updating = YES;
                //進到這里說明用戶正在上拉加載,觸發(fā)mj,此時要關(guān)閉翻頁功能否則頁面回彈mj_footer就看不到了拍柒,setContentOffset也無效
                self.tableView.pagingEnabled = NO;
                //給tableView設(shè)置一個固定的Offset心傀,往上偏移點,將footer展示出來拆讯,要大于44才會觸發(fā)footer
                [self.tableView setContentOffset:CGPointMake(0, index*kHeight+50) animated:NO];
                [self.tableView.mj_footer beginRefreshing];
            }
            
        }
    }
    else if (offset<0)
    {
        if (_tableView.updating==YES) {
            //如果用戶上拉加載時脂男,又進行下滑操作阵子,就要打開翻頁功能(可能加載時間長用戶不想等又往上翻之前的cell)-這種情況少見但不排除粘姜,不做此操作的話,將請求延時十秒就會看到區(qū)別颤难,但一旦用戶有這種操作就會有閃屏問題爽室,即用戶在第10個cell上拉加載了汁讼,然后又下滑倒第5個cell,當(dāng)拿到返回數(shù)據(jù)之后頁面會從5自動滾動到第11個cell阔墩,造成閃屏嘿架,但在3G網(wǎng)絡(luò)下經(jīng)測試抖音也是這樣,故就這樣吧
            self.tableView.pagingEnabled = YES;
        }
        
    }
}

到此就算搞定上拉加載了啸箫。

如果你使用時有什么問題耸彪,請留言。

感謝NewPan大神的JPVideoPlayer實現(xiàn)了抖音的自動播放

如果對您有幫助記得點贊收藏哦^?_?^

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末筐高,一起剝皮案震驚了整個濱河市搜囱,隨后出現(xiàn)的幾起案子丑瞧,更是在濱河造成了極大的恐慌,老刑警劉巖蜀肘,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绊汹,死亡現(xiàn)場離奇詭異,居然都是意外死亡扮宠,警方通過查閱死者的電腦和手機西乖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坛增,“玉大人获雕,你說我怎么就攤上這事∈盏罚” “怎么了届案?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長罢艾。 經(jīng)常有香客問我楣颠,道長,這世上最難降的妖魔是什么咐蚯? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任童漩,我火速辦了婚禮,結(jié)果婚禮上春锋,老公的妹妹穿的比我還像新娘矫膨。我一直安慰自己,他們只是感情好期奔,可當(dāng)我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布侧馅。 她就那樣靜靜地躺著,像睡著了一般呐萌。 火紅的嫁衣襯著肌膚如雪施禾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天搁胆,我揣著相機與錄音,去河邊找鬼邮绿。 笑死渠旁,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的船逮。 我是一名探鬼主播顾腊,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼挖胃!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤饵沧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后掠归,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡余寥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年祝蝠,在試婚紗的時候發(fā)現(xiàn)自己被綠了细溅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蹦狂。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡啊研,死狀恐怖党远,靈堂內(nèi)的尸體忽然破棺而出削解,到底是詐尸還是另有隱情,我是刑警寧澤沟娱,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布氛驮,位于F島的核電站,受9級特大地震影響济似,放射性物質(zhì)發(fā)生泄漏矫废。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一砰蠢、第九天 我趴在偏房一處隱蔽的房頂上張望蓖扑。 院中可真熱鬧,春花似錦台舱、人聲如沸律杠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽柜去。三九已至,卻和暖如春拆宛,著一層夾襖步出監(jiān)牢的瞬間嗓奢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工浑厚, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留股耽,地道東北人。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓钳幅,卻偏偏與公主長得像豺谈,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子贡这,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,440評論 2 348

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