丟棄MJRefresh吧,封裝自己的刷新控件揩尸。

實際開發(fā)中很多時候使用的一些刷新控件可能都是MJRefresh蛹屿,但是實際上一些比較牛逼的應(yīng)用程序為了凸顯自己的個性,往往連刷新控件都是很對弈無二的岩榆。今天就說下如何封裝自己的刷新控件错负,實現(xiàn)起來核心代碼也就不到一百多行的樣子坟瓢,里面的邏輯也并不是很復(fù)雜,使用起來也很方面犹撒,基本調(diào)用形式和MJRefresh一樣折联。這篇文章主要以下拉刷新來說明,至于上拉加載基本理解了下拉刷新识颊,就是一個模子刻出來的诚镰。會有源碼提供,源碼中既包含該上拉也包含下拉谊囚。下載鏈接:https://github.com/ZhengYaWei1992/ZWRefreshDemo
先看效果圖:

下拉刷新

上拉加載

效果圖看的還行怕享,接下來看看如何實現(xiàn)吧。
首先來看一下镰踏,如何使用的函筋,其實實際上上使用起來,外部調(diào)用形式和MJRefres基本差不多的奠伪,根本不需要自己手動創(chuàng)建刷新控價跌帐,直接調(diào)用tableView的屬性即可。其實這一點也不是很神奇绊率,主要就是基于runtime的關(guān)聯(lián)對象實現(xiàn)的谨敛,幾行代碼就可以實現(xiàn)這樣的效果。

//==================下拉刷新===================
    self.tableView.refreshHeaderView.refreshingBlock = ^(){
        NSLog(@"這里調(diào)用下拉刷新的方法");
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            for (int i = 0; i < 5; i++) {
                 [weakSelf.dataSource insertObject:@"刷新增加的數(shù)據(jù)" atIndex:0];
            }
            [weakSelf.tableView reloadData];
            //結(jié)束刷新
            [weakSelf.tableView.refreshHeaderView endRefreshing];
        });
    };
    //初次加載控制器滤否,直接刷新
    [self.tableView.refreshHeaderView startRefreshing];

上拉加載調(diào)用形式

//================上拉加載===================
    self.tableView.refreshFooterView.refreshingBlock = ^(){
        NSLog(@"這里調(diào)用上拉加載的方法");
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            for (int i = 0; i < 5; i++) {
                [weakSelf.dataSource addObject:@"上拉加載更多數(shù)據(jù)"];
            }
            [weakSelf.tableView reloadData];
            //結(jié)束刷新
            [weakSelf.tableView.refreshFooterView endRefreshing];
        });
    };

看看如何實現(xiàn)吧脸狸,說明實現(xiàn)主要是針對下拉刷新說明的。首先建一個繼承與UIView的ZWPullDownToRefreshView藐俺。并在.h文件中添加一個刷新回調(diào)屬性和開始刷新炊甲、以及結(jié)束刷新的方法。至于刷新控價里面要顯示的內(nèi)容欲芹,這個可以根據(jù)自己的實際需求自定義各種樣式卿啡。

@property(nonatomic,copy)void(^refreshingBlock)();
//結(jié)束刷新
- (void)endRefreshing;
//開始刷新
- (void)startRefreshing;

重寫系統(tǒng)的willMoveToSuperview:個方法,并在里面監(jiān)控父視圖的contentOffset屬性(可能是tableView菱父、CollectionView颈娜、scrollView)。根據(jù)contentSize屬性值的變化來監(jiān)聽不同的狀態(tài)浙宜,主要分為三種狀態(tài):ZWPullDownToRefreshViewStatusNormal,//正常
ZWPullDownToRefreshViewStatusPulling,//釋放刷新
ZWPullDownToRefreshViewStatusRefreshing,//正在刷新
這三種狀態(tài)官辽,可以通過枚舉值設(shè)置。
說明:willMoveToSuperview:這個方法在父視圖調(diào)用addSubView方法的時候會調(diào)用這個方法粟瞬。

//在控制器中調(diào)用[self.tableView addSubview:refreshView];會調(diào)用這個方法
- (void)willMoveToSuperview:(UIView *)newSuperview{
    [super willMoveToSuperview:newSuperview];
    //這里可以獲取到父控件 tableView野崇、scrollView、collection,在本類中監(jiān)聽父控件的滾動
    if ([newSuperview isKindOfClass:[UIScrollView class]]) {
        self.superScrollView = (UIScrollView *)newSuperview;
        //監(jiān)聽父控件elf.superScrollView的滾動  即contentOffset屬性
        //最好通過KVO監(jiān)聽亩钟;如果通過代理監(jiān)聽乓梨,外部再次設(shè)置代理會使這里面的監(jiān)聽滾動會失效
        //本類self監(jiān)聽self.superScrollView的contentOffset屬性
        [self.superScrollView addObserver:self forKeyPath:@"contentOffset" options:0 context:nil];
    }
}

監(jiān)聽事件的實現(xiàn)。這里要明確的區(qū)別幾種刷新的狀態(tài)清酥,集中狀態(tài)是通過currentStatus屬性記錄的扶镀。通過調(diào)用currentStatus屬性set方法切換刷新控件的不同樣式。
三種狀態(tài):
ZWPullDownToRefreshViewStatusNormal,//正常
ZWPullDownToRefreshViewStatusPulling,//釋放刷新
ZWPullDownToRefreshViewStatusRefreshing,//正在刷新
當(dāng)手在拖動的時候焰轻,一般只是在兩種狀態(tài)中切化即normal和pulling狀態(tài)臭觉;當(dāng)手不在拖動的時候,并且當(dāng)前的狀態(tài)處于pulling 狀態(tài)的時候辱志,會從pulling狀態(tài)切換到刷新狀態(tài)refreshing蝠筑,處于刷新狀態(tài)的時候要額外再次調(diào)節(jié)刷新控件的位置,而不是依據(jù)contentOffset的屬性值設(shè)置揩懒。

#pragma mark - KVC監(jiān)聽事件
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    if ([keyPath isEqualToString:@"contentOffset"]) {
        //NSLog(@"%f",self.superScrollView.contentOffset.y);
        //拖動中:normal -> pulling   pulling ->normal
        if (self.superScrollView.isDragging) {//手在拖動
            //在控制器中self.superScrollView中初始contentOffset.y為-64
            CGFloat normalPullingOffset = - 2 * ZWRefreshViewHeight;
            if (self.superScrollView.contentOffset.y > normalPullingOffset && self.currentStatus == ZWPullDownToRefreshViewStatusPulling){
                //NSLog(@"從pulling切換到normal狀態(tài)");
                self.currentStatus = ZWPullDownToRefreshViewStatusNormal;
            }else if(self.superScrollView.contentOffset.y <= normalPullingOffset && self.currentStatus == ZWPullDownToRefreshViewStatusNormal){
                //NSLog(@"從normal切換到pulling狀態(tài)");
                self.currentStatus = ZWPullDownToRefreshViewStatusPulling;
            }
        }else{//松開:pulling -> refreshing
            if (self.currentStatus == ZWPullDownToRefreshViewStatusPulling) {
                //NSLog(@"從pulling切換到Refreshing狀態(tài)");
                self.currentStatus = ZWPullDownToRefreshViewStatusRefreshing;
            }
        }
    }
}

通過調(diào)用currentStatus屬性的set方法切換刷新控件的不同形式什乙。這里的刷新控件我主要是使用了一個imageView和一個label來顯示效果。實際想要使用的時候已球,只要給這兩個控件給替換了就行臣镣,在setCurrentStatus:方法中根據(jù)不同的三種刷新狀態(tài)改變樣式,既可以實現(xiàn)自定義刷新效果智亮,想要什么效果就可以達(dá)到什么效果忆某。

- (void)setCurrentStatus:(ZWPullDownToRefreshViewStatus)currentStatus{
    _currentStatus = currentStatus;
    //設(shè)置內(nèi)容
    switch (_currentStatus) {
        case ZWPullDownToRefreshViewStatusNormal:
            //結(jié)束動畫
            [self.imageView stopAnimating];
            self.label.text = @"下拉刷新";
            self.imageView.image = [UIImage imageNamed:@"normal"];
            
            break;
        case ZWPullDownToRefreshViewStatusPulling:
            self.label.text = @"釋放刷新";
            self.imageView.image = [UIImage imageNamed:@"pulling"];
            break;
        case ZWPullDownToRefreshViewStatusRefreshing:
            self.label.text = @"正在刷新";
            
            self.imageView.animationImages = self.refreshingImages;
            self.imageView.animationDuration = 0.1 * self.refreshingImages.count;
            [self.imageView startAnimating];
            
            //說明:系統(tǒng)很多動畫時間都是0.25s
            [UIView animateWithDuration:0.25 animations:^{
                //self.superScrollView往下走
                self.superScrollView.contentInset = UIEdgeInsetsMake(self.superScrollView.contentInset.top + ZWRefreshViewHeight, self.superScrollView.contentInset.left, self.superScrollView.contentInset.bottom, self.superScrollView.contentInset.right);
            }];
            //讓控制器做事情
            if (self.refreshingBlock) {
                self.refreshingBlock();
            }
            break;
    }
}

再來看看開始刷新和結(jié)束刷新的實現(xiàn)代碼。

//開始刷新
- (void)startRefreshing{
    self.currentStatus = ZWPullDownToRefreshViewStatusRefreshing;
}
//結(jié)束刷新
- (void)endRefreshing{
    //refreshing  -> normal
    if (self.currentStatus == ZWPullDownToRefreshViewStatusRefreshing) {
        self.currentStatus = ZWPullDownToRefreshViewStatusNormal;
        //tableView回去
        [UIView animateWithDuration:0.25 animations:^{
            //self.superScrollView往下走
            self.superScrollView.contentInset = UIEdgeInsetsMake(self.superScrollView.contentInset.top - ZWRefreshViewHeight, self.superScrollView.contentInset.left, self.superScrollView.contentInset.bottom, self.superScrollView.contentInset.right);
        }];
    }
}

這就基本實現(xiàn)了自定義刷新控件的目的阔蛉,但是如何達(dá)到類似 self.tableView.refreshFooterView.refreshingBlock = ^(){}這樣的調(diào)用形式弃舒。很簡單新建一個UISrcollView的分類UIScrollView+Refresh,然后借助運行時添加如下關(guān)聯(lián)屬性(頭部刷新控件和底部刷新控件)状原。這樣的話每次在調(diào)用self.tableView.refreshFooterView的時候聋呢,就會調(diào)用分類中refreshHeaderView的getter和setter方法坝冕,自動創(chuàng)建刷新控件,不在需要自己在外部手動創(chuàng)建。就是這些就實現(xiàn)了稳摄,不能像MJRefresh那樣靈活的直接調(diào)用,但是通過更改里面的源碼昌讲,完全可以實現(xiàn)封裝任何自己想要的樣式短绸。

//上拉加載控件  底部
@property(nonatomic,strong)ZWPullUpToLoadView *refreshFooterView;
//下拉刷新控件  頭部
@property(nonatomic,strong)ZWPullDownToRefreshView *refreshHeaderView;
#pragma mark - 頭部刷新控件關(guān)聯(lián)對象
-(void)setRefreshHeaderView:(ZWPullDownToRefreshView *)refreshHeaderView{
    objc_setAssociatedObject(self, refreshHeaderKey, refreshHeaderView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (ZWPullDownToRefreshView *)refreshHeaderView{
    ZWPullDownToRefreshView *refreshHeaderView = objc_getAssociatedObject(self, refreshHeaderKey);
    if (refreshHeaderView == nil) {
        refreshHeaderView = [[ZWPullDownToRefreshView alloc]initWithFrame:CGRectMake(0, -ZWRefreshViewHeight, [UIScreen mainScreen].bounds.size.width, ZWRefreshViewHeight)];
         //保存對象
         self.refreshHeaderView = refreshHeaderView;
         [self addSubview:refreshHeaderView];
    }
    return refreshHeaderView;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末扎运,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子烦衣,更是在濱河造成了極大的恐慌厨姚,老刑警劉巖今布,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件傅蹂,死亡現(xiàn)場離奇詭異,居然都是意外死亡波桩,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門请敦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人储玫,你說我怎么就攤上這事侍筛。” “怎么了撒穷?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵匣椰,是天一觀的道長。 經(jīng)常有香客問我端礼,道長禽笑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任蛤奥,我火速辦了婚禮佳镜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凡桥。我一直安慰自己蟀伸,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布缅刽。 她就那樣靜靜地躺著啊掏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪衰猛。 梳的紋絲不亂的頭發(fā)上迟蜜,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機(jī)與錄音啡省,去河邊找鬼娜睛。 笑死,一個胖子當(dāng)著我的面吹牛冕杠,可吹牛的內(nèi)容都是我干的微姊。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼分预,長吁一口氣:“原來是場噩夢啊……” “哼兢交!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起笼痹,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤配喳,失蹤者是張志新(化名)和其女友劉穎酪穿,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晴裹,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡被济,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了涧团。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片只磷。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖泌绣,靈堂內(nèi)的尸體忽然破棺而出钮追,到底是詐尸還是另有隱情,我是刑警寧澤阿迈,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布元媚,位于F島的核電站,受9級特大地震影響苗沧,放射性物質(zhì)發(fā)生泄漏刊棕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一待逞、第九天 我趴在偏房一處隱蔽的房頂上張望甥角。 院中可真熱鬧,春花似錦飒焦、人聲如沸蜈膨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翁巍。三九已至,卻和暖如春休雌,著一層夾襖步出監(jiān)牢的瞬間灶壶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工杈曲, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留驰凛,地道東北人。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓担扑,卻偏偏與公主長得像恰响,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子涌献,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,737評論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫胚宦、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,059評論 4 62
  • 01 有些男生連一個女生性格、人品怎么樣都不知道 枢劝,光看一張照片就說喜歡 井联。 朋友的朋友松鼠是個一米八幾...
    橘里s閱讀 647評論 4 4
  • 【人物】有一個中國民營企業(yè)家,是中國最受國際尊重的企業(yè)家您旁,他狂賺老外13800億烙常,然而他的座駕卻是不到十萬的二...
    李廿閱讀 1,383評論 1 2