淺讀MJRefresh后自定義了個UIScrollView監(jiān)聽滾動的block屬性

一懂缕、前言

最近在解答[最新版]MJRefresh解析與詳細使用指導MJRefresh實現(xiàn)刷新(使用它的Block方法)中簡友的提問顿天,淺讀了下MJRefresh的源碼(關于源碼解讀,網上已有很多惫皱,我后續(xù)也會寫一篇我自己的解讀健田,不過今天要說的是:借鑒別人的思路,做or完善自己的事晃痴。):利用KVO在- (void)willMoveToSuperview:(UIView *)newSuperview方法調用時監(jiān)聽scrollView的contentOffset/contentSize和panGestureRecognizer的state屬性,然后做對應操作财忽。

二倘核、開發(fā)困惑

通常,作為iOS開發(fā)人員即彪,判斷UIScrollView/UITableView/UICollectionView的滾動情況的事笤虫,時有發(fā)生。如果每次都去實現(xiàn)delegate方法,在我看來祖凫,有些麻煩琼蚯。除了一遍一遍的寫代理,還有一種就是建個基類惠况,但是這樣基類還是要實現(xiàn)對應的delegate方法遭庶。

三、解決方法:給UIScrollView添加block屬性監(jiān)聽滾動

先預覽下效果(上面紅色的是手機錄屏所致)

效果圖

四稠屠、理清思路

  1. 新建一個類PPMJRefreshComponent,類似MJRefresh中的MJRefreshComponent峦睡,用來當做觀察者;
  2. 既然PPMJRefreshComponent要觀察UIScrollViewcontentOffset以及panGestureRecognizerstate,那么PPMJRefreshComponent就要關聯(lián)當前的UIScrollView;并且权埠,UIScrollView要擁有一個PPMJRefreshComponent對象(如下圖:)榨了;
componet和scrollView相互關系
  1. PPMJRefreshComponent觀察的結果怎么傳遞給UIScrollView?我采用的是delegate(PPMJRefreshComponentDelegate),需要UIScrollView對象遵守攘蔽;(此處不使用block是因為block嵌套block容易出問題)
PPMJRefreshComponentDelegate.png
  1. UIScrollView對象實現(xiàn)代理龙屉,并設置scrollBlock的時候觸發(fā)監(jiān)聽:(代碼如下,注釋已寫進去)
@implementation UIScrollView (ScrollBlock)

#pragma mark --- PPMJRefreshComponentDelegate
-(void)scrollViewContentOffsetDidChange:(NSDictionary<NSKeyValueChangeKey,id> *)change{
     [self contentOffsetBlockAction:change];
}
-(void)scrollViewPanStateDidChange:(NSDictionary<NSKeyValueChangeKey,id> *)change{
    [self panGestureRecognizerStateAction:change];
}

-(void)contentOffsetBlockAction:(NSDictionary<NSKeyValueChangeKey,id> *)change
{
    //這個屬性字面理解意思為:正在拖動满俗。實際上是:scrollView是否滾動了转捕,只要不是最開始初始化的時候設置的位置,就為YES唆垃。
    if (!self.isDragging) {
        return;
    }
    //【注意】此處要特別注意五芝,如果設置contentInset的話,要給pp_lastContentOffsetY賦值為insetT的初始值
    if (!self.pp_lastContentOffsetY) {
        [self setupInitializeOffsetY];
    }
    //獲取當前的contentOffsetY
    CGFloat currentContentOffsetY = self.pp_FSB_offsetY;
   
    //如果前后的contentOffsetY值相同辕万,就不做處理
    CGFloat lastContentOffsetY = [self.pp_lastContentOffsetY floatValue];
    if (currentContentOffsetY == lastContentOffsetY) {
        return;
    }

    //是否是向上滑枢步,初始值為NO
    BOOL isToUp = NO;

    //向上滑動
    if (currentContentOffsetY > lastContentOffsetY) {
        //處理滑動到底部,繼續(xù)上滑后系統(tǒng)自動反彈而重復調用的情況
        if (currentContentOffsetY+self.pp_h > self.pp_FSB_contentH) {
            return;
        }
        isToUp = YES;
        
    }else{
        //向下滑動
        //處理已經最上面了仍然下拉而反彈時渐尿,反復調用
        if (currentContentOffsetY <= self.pp_FSB_insetT) {
            return;
        }
        
    }
    
    //給pp_lastContentOffsetY綁定值
    objc_setAssociatedObject(self, @selector(pp_lastContentOffsetY), [NSNumber numberWithFloat:currentContentOffsetY], OBJC_ASSOCIATION_RETAIN);
    
    //是否超過一個屏幕
    BOOL isInOneScreen = (self.pp_FSB_insetT+self.pp_FSB_contentH <= self.pp_h);
    
    if (self.pp_scrollBlock) {
        self.pp_scrollBlock(currentContentOffsetY, isToUp,isInOneScreen);
    }

}
-(void)panGestureRecognizerStateAction:(NSDictionary<NSKeyValueChangeKey,id> *)change
{
    if (self.panGestureRecognizer.state == UIGestureRecognizerStateEnded) {
        //內容不夠一個屏幕時醉途,系統(tǒng)會自動回彈,這時候記得把pp_lastContentOffsetY重新設置一下
        if (self.pp_FSB_insetT+self.pp_FSB_contentH <= self.pp_h) {
            [self setupInitializeOffsetY];
        }else{
            //超過一個屏幕,這時候下拉涡戳,當松開的時候要把pp_lastContentOffsetY重新設置一下
            if (self.pp_FSB_offsetY < self.pp_FSB_insetT) {
                [self setupInitializeOffsetY];
            }
        }
    }
    
}

#pragma mark --- 初始化contentOffsetY的值
-(void)setupInitializeOffsetY{
    CGFloat currentContentOffsetY = -self.pp_FSB_insetT;
    objc_setAssociatedObject(self, @selector(pp_lastContentOffsetY), [NSNumber numberWithFloat:currentContentOffsetY], OBJC_ASSOCIATION_RETAIN);
}

-(void)setPp_scrollBlock:(PPUIScrollViewScrollBlock)pp_scrollBlock
{
    //在設置scrollBlock的時候结蟋,觸發(fā)監(jiān)聽
    self.pp_component.delegate = self;
    objc_setAssociatedObject(self, @selector(pp_scrollBlock), pp_scrollBlock, OBJC_ASSOCIATION_RETAIN);
}
-(PPUIScrollViewScrollBlock)pp_scrollBlock
{
   return objc_getAssociatedObject(self, _cmd);
}
@end

針對上面的代碼補充說明如下:

  1. 注意component的初識與關聯(lián),一定要弄懂為啥我代碼中要用runtime強制關聯(lián);
  2. 注意pp_lastContentOffsetY的使用渔彰,它是給UIScrollView動態(tài)綁定的記錄上一次的contentOffsetY值的嵌屎,只有在滑動的時候有效推正,最終如果你放外部的話,偏移量還是和contentOffset.Y的值一樣宝惰。
  3. -(void)contentOffsetBlockAction:(NSDictionary<NSKeyValueChangeKey,id> *)change這個方法處理滑動情況植榕,但是開始下拉上拉到底的兩種臨街狀態(tài)時的pp_lastContentOffsetY需要特殊處理,而這個處理就放在panGestureRecognizer.state == UIGestureRecognizerStateEnded的時候尼夺。

最后尊残,感謝MJRefresh

文字無法描述這個過程淤堵,當時怎么想寝衫,做的時候怎么做,后來又是怎么調整的拐邪,說多了慰毅,就失去了文章的核心,所以:感興趣的最好看下代碼扎阶,有不懂的請問我汹胃,盡我之力,一起學習东臀。

2018-03-08 14:20:40 婦女節(jié)快樂着饥!感謝公司的party,此刻吃著零食喝著飲料,匆匆結文惰赋。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末宰掉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子谤逼,更是在濱河造成了極大的恐慌贵扰,老刑警劉巖仇穗,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件流部,死亡現(xiàn)場離奇詭異,居然都是意外死亡纹坐,警方通過查閱死者的電腦和手機枝冀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來耘子,“玉大人果漾,你說我怎么就攤上這事」仁模” “怎么了绒障?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長捍歪。 經常有香客問我户辱,道長鸵钝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任庐镐,我火速辦了婚禮恩商,結果婚禮上,老公的妹妹穿的比我還像新娘必逆。我一直安慰自己怠堪,他們只是感情好,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布名眉。 她就那樣靜靜地躺著粟矿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪损拢。 梳的紋絲不亂的頭發(fā)上嚷炉,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天,我揣著相機與錄音探橱,去河邊找鬼申屹。 笑死,一個胖子當著我的面吹牛隧膏,可吹牛的內容都是我干的哗讥。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼胞枕,長吁一口氣:“原來是場噩夢啊……” “哼杆煞!你這毒婦竟也來了?” 一聲冷哼從身側響起腐泻,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤决乎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后派桩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體构诚,經...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年铆惑,在試婚紗的時候發(fā)現(xiàn)自己被綠了范嘱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡员魏,死狀恐怖丑蛤,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情撕阎,我是刑警寧澤受裹,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站虏束,受9級特大地震影響棉饶,放射性物質發(fā)生泄漏脑慧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一砰盐、第九天 我趴在偏房一處隱蔽的房頂上張望闷袒。 院中可真熱鬧,春花似錦岩梳、人聲如沸囊骤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽也物。三九已至,卻和暖如春列疗,著一層夾襖步出監(jiān)牢的瞬間滑蚯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工抵栈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留告材,地道東北人。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓古劲,卻偏偏與公主長得像斥赋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子产艾,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內容