利用RAC一句話實(shí)現(xiàn)上拉下拉刷新

最近在研究上拉刷新下拉刷新,有點(diǎn)小心得和大家分享下。

首先我是先在網(wǎng)上搜博客看,發(fā)現(xiàn)要不就是用原生UIRefreshControl要不就是第三方庫(kù)的教程,這都不是我想要的(好的開(kāi)源庫(kù)推薦MJRefresh)。

于是我開(kāi)始看大神們的源代碼,了解了下原理。

刷新原理

首先上拉下拉刷新肯定是基于UIScrollView的基礎(chǔ)上的,包括UITableView其實(shí)也是一個(gè)UIScrollView。而實(shí)現(xiàn)上拉下拉刷新的原理就是UIScrollView中的代理方法

- (void)scrollViewDidScroll:(UIScrollView *)scrollView;// any offset changes

這個(gè)方法是在你的scrollView滾動(dòng)時(shí)就會(huì)執(zhí)行的方法。

這里有必要說(shuō)明下scrollView的兩個(gè)屬性,一個(gè)是contentSize,一個(gè)是contentOffset。這里上圖片講解可能直觀一點(diǎn)。

wait
wait

PS:不會(huì)用mac的畫圖工具比較丑見(jiàn)諒。

看圖,這里的綠色框就是我們的手機(jī)屏幕,我們的UI都是呈現(xiàn)在手機(jī)屏幕上的,那么黑色的框就是contentSize。就是說(shuō),雖然手機(jī)屏幕只有一點(diǎn)大,但是我們的scrollView并不是只有一點(diǎn)大的,這個(gè)屬性是可以設(shè)置的,而我們滾動(dòng)scrollView其實(shí)就是滾動(dòng)黑色框,這樣看到的界面就會(huì)不一樣了。而圖上標(biāo)注的紅點(diǎn)就是contentOffset。contentOffset是一個(gè)CGPoint,代表當(dāng)前屏幕所在位置左上角相對(duì)于scrollView.contentSize左上角的橫縱坐標(biāo)值。

了解了scrollView我們就來(lái)說(shuō)刷新。在
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;// any offset changes方法中我們應(yīng)該監(jiān)聽(tīng)contentOffset的值,如果他的縱坐標(biāo)到某個(gè)點(diǎn)以上我們就執(zhí)行刷新數(shù)據(jù),移動(dòng)到某個(gè)點(diǎn)以下我們就執(zhí)行加載數(shù)據(jù)。具體看代碼可能更好理解。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView 
{
if ([scrollView isEqual:_tableView]) {
    if (scrollView.contentOffset.y < -50 ) {
    //下拉刷新方法
    }
    if (scrollView.contentOffset.y > 800 ) {
    //上拉加載方法
    }
  }
}

原理很簡(jiǎn)單,但是實(shí)現(xiàn)的話還是有很多細(xì)節(jié)需要考慮的,比如scrollView.contentOffset.y < -50的情況是很多的,當(dāng)用戶快速上拉到-100時(shí),可能在-51執(zhí)行一次刷新方法,在-52執(zhí)行一次,-53執(zhí)行一次。。。。。。這肯定是不合理的。

所以我們需要節(jié)流。這里提兩個(gè)我的個(gè)人觀點(diǎn),一個(gè)是開(kāi)線程執(zhí)行刷新辦法,如果線程存在不會(huì)新開(kāi)一個(gè),這樣可以保證刷新方法執(zhí)行一次。還有一種是用KVO監(jiān)聽(tīng)用戶手指松開(kāi)的動(dòng)作,松開(kāi)的時(shí)候再刷新,或者- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate用這個(gè)代理方法,他會(huì)幫你監(jiān)聽(tīng)手指是否松開(kāi)。這兩個(gè)方法我都沒(méi)試過(guò),大家可以自己嘗試下,有錯(cuò)希望反饋給我,共同進(jìn)步。

但是如果僅僅是判定松開(kāi)我覺(jué)得是滿足不了需求的。我現(xiàn)在希望就是當(dāng)用戶快下滑到底部時(shí)就自動(dòng)加載新數(shù)據(jù),那我應(yīng)該怎么實(shí)現(xiàn)呢?總不能用戶一拉到底不松手就不加載吧。

RAC一個(gè)方法實(shí)現(xiàn)刷新

我想到了RAC。這個(gè)想法可能有點(diǎn)非主流,所以肯定有邏輯考慮不周的地方,希望各位指出。這里我先宏定義了下,為了縮短代碼

#define VIEWHEIGHT self.view.frame.size.height

然后就是RAC了。

[[[RACObserve(self.tableView, contentOffset) map:^id(id value) {
    if (self.tableView.contentOffset.y < -50) {
        return @"1";
    }
    if (self.tableView.contentOffset.y > self.tableView.contentSize.height - VIEWHEIGHT * 1.5 && self.tableView.contentSize.height - VIEWHEIGHT * 1.5 > 0) {
        return @"2";
    }else{
        return @"0";
    }
}] distinctUntilChanged] subscribeNext:^(id x) {
    debugLog(@"%@", x);
    if ([x integerValue] == 1) {
        [self netWork];
    }else if ([x integerValue] == 2){
        [self loadMoreData];
    }
}];

這里是用了RAC KVO的寫法,不會(huì)的可以點(diǎn)我文章復(fù)習(xí)下。首先寫了一個(gè)通知監(jiān)聽(tīng)tableView的contentOffset,如果發(fā)生變化立刻進(jìn)入map產(chǎn)生的映射中執(zhí)行map中的方法。我給情況分了類,如果用戶下拉,返回1,如果上拉快到底部時(shí)返回2。并且在映射完成后用了distinctUntilChanged屬性,當(dāng)我的映射值不產(chǎn)生變化時(shí)是不會(huì)傳遞映射值的。這樣當(dāng)用戶拉倒需要刷新的位置,只會(huì)發(fā)一個(gè)信號(hào)給訂閱者,只會(huì)執(zhí)行一次刷新數(shù)據(jù)的方法,這樣我所有的需求就迎刃而解了。

如果有更好的辦法希望大家給我指出,謝謝大家。也歡迎來(lái)我的博客看看

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容