效果圖--------
實(shí)現(xiàn)思路
結(jié)構(gòu)解析
一、下拉刷新實(shí)現(xiàn)
導(dǎo)入#import "UIScrollView+CLRefreshView.h"
,添加滾動(dòng)視圖的刷新效果,在基類中創(chuàng)建刷新工具類,以便子類UITableView
、UIScrollView
通用。
/** 下拉刷新 */
- (void)setUpSimpleHeader{
__weak typeof (self) weakSelf = self;
[self.tabelview cl_addRefreshHeaderViewWithAction:^{
[weakSelf loadHeaderData:kLoadOptionHeader];
}];
}
在分類中,因?yàn)椴荒芴砑訉傩裕?code>#import <objc/runtime.h>使用runtime機(jī)制,將vc上傳入的滾動(dòng)視圖,進(jìn)行刷新視圖綁定
- (void)setCl_refreshHeader:(CLRefreshHeader *)cl_refreshHeader{
[self willChangeValueForKey:@"CLRefreshHeaderViewKey"];
objc_setAssociatedObject(self, &CLRefreshHeaderViewKey, cl_refreshHeader,OBJC_ASSOCIATION_ASSIGN);
[self didChangeValueForKey:@"CLRefreshHeaderViewKey"];
}
- (CLRefreshHeader *)cl_refreshHeader{
return objc_getAssociatedObject(self, &CLRefreshHeaderViewKey);
}
通過set方法將傳入的滾動(dòng)視圖,綁定& CLRefreshHeaderViewKey唯一標(biāo)識(shí)。這里針對(duì)的是唯一字符串的地址空間,這樣的好處是不會(huì)重復(fù)綁定。實(shí)現(xiàn)了唯一性。字符串static char CLRefreshHeaderViewKey;
一、具體實(shí)現(xiàn)思路:CLAbstractRefreshView抽象類,執(zhí)行刷新狀態(tài)的監(jiān)聽
/** 不同時(shí)機(jī)下的刷新狀態(tài) */
typedef enum {
CLRefreshViewStateNormal = 1,//滾動(dòng)視圖滑動(dòng)但是,未觸發(fā)加載時(shí)機(jī)
CLRefreshViewStateWillLoading,//滾動(dòng)視圖滑動(dòng),且觸發(fā)到最大下拉距離的時(shí)機(jī)
CLRefreshViewStateLoading//正在加載中
}CLRefreshViewState;
編寫下拉刷新的關(guān)鍵是考慮contentOffset以及contentInsert,前者用來判斷當(dāng)前手勢(shì)下滑進(jìn)行的進(jìn)度和程度,從而去判斷刷新視圖進(jìn)行的狀態(tài)變化,并借由它將進(jìn)度傳入動(dòng)畫視圖去執(zhí)行動(dòng)畫流程。
/** 抽象類中的基本協(xié)議 */
@protocol CLRefreshControl <NSObject>
@optional
- (void)refreshViewChangeUIWhenNormal;//執(zhí)行 1
- (void)refreshViewChangeUIWhenWillLoading;//執(zhí)行 2
- (void)refreshViewChangeUIWhenLoading;//執(zhí)行 3
- (void)refreshViewChangeUIWhenFinishLoading;// 滾動(dòng)視圖復(fù)位
@end
/** 這是一個(gè)刷新的抽象類 */
@class CLAbstractLoadingView;
@interface CLAbstractRefreshView : UIView<CLRefreshControl>
@property (nonatomic, weak, readonly) UIScrollView *scrollView;
@property (nonatomic, assign, readonly) UIEdgeInsets scrollViewOriginalInserts;//記錄滾動(dòng)視圖的原始Insets
@property (nonatomic, copy) void (^refreshAction)();
@property (nonatomic, assign) CLRefreshViewState state;//記錄當(dāng)前刷新的狀態(tài)
@property (nonatomic, assign, readonly) CLRefreshViewState previousState;//記錄之前的刷新狀態(tài)
/** 加載動(dòng)畫視圖 */
@property (nonatomic, weak) CLAbstractLoadingView *loadingView;
/** 獲取當(dāng)前滾動(dòng)視圖里下拉時(shí)機(jī)的進(jìn)度 */
@property (nonatomic, assign, readonly) CGFloat showProgress;
/** 創(chuàng)建下拉視圖 */
+ (instancetype)refreshView;
- (void)endRefresh;//結(jié)束和開始刷新是,提供的抽象方法,是通用的
- (void)startRefresh;
#pragma mark -子類實(shí)現(xiàn)
/**
* 根據(jù)滾動(dòng)視圖的屬性計(jì)算出,空間將要顯示的位置
*
* @param scrollViewInsets <#scrollViewInsets description#>
* @param offset <#offset description#>
*
* @return 控價(jià)顯示的百分比進(jìn)度,如果控件直接處與屏幕外,返回-1.父類默認(rèn)返回-1
*/
- (CGFloat)showProgress:(UIEdgeInsets)scrollViewInsets scrollViewOffset:(CGPoint)offset;
/**
* 控件將要顯示的位置,由Header子類實(shí)現(xiàn),F(xiàn)ooter子類此方法無意義
*
* @return 控件剛加入滾動(dòng)視圖時(shí),將要顯示的位置,默認(rèn)返回(0,0)
*/
- (CGPoint)willShowPoint;
使用多態(tài),提高程序的可讀性。
子類CLSimpleRefreshHeader
( 這個(gè)類主要去實(shí)現(xiàn)細(xì)節(jié),比如不同時(shí)機(jī)下的提示語句,還有創(chuàng)建動(dòng)畫視圖),父類CLRefreshHeader
(實(shí)現(xiàn)對(duì)視圖不同狀態(tài)下,位置的設(shè)置),抽象類CLAbstractRefreshView
(監(jiān)聽手勢(shì)滑動(dòng)去實(shí)現(xiàn)刷新視圖狀態(tài)的改變以及動(dòng)畫視圖的繪制進(jìn)度調(diào)整)
子類CLCircleLoadingView
(繪制動(dòng)畫),抽象類CLAbstractLoadingView
(設(shè)置繪畫的進(jìn)度)
/** 提供添加下拉刷新的視圖 */
- (void)cl_addRefreshHeaderViewWithAction:(void(^)())action{
CLRefreshHeader *header = [CLSimpleRefreshHeader refreshView];
header.refreshAction = action;
[self cl_addRefreshHeaderView:header];
}
二、上拉刷新
子類CLSimpleRefreshFooter
(創(chuàng)建動(dòng)畫視圖CLCircleLoadingView),父類CLRefreshFooter
(通過上拉狀態(tài)設(shè)置滾動(dòng)視圖的固定位置),抽象類CLAbstractRefreshView
(設(shè)置不同的刷新狀態(tài)監(jiān)聽)。
注意的一點(diǎn):上拉刷新
在界面內(nèi)容過少的時(shí)候,應(yīng)該顯示“加載更多的提示按鈕”。與下拉通過contentOffset不同現(xiàn)在監(jiān)聽的是滾動(dòng)視圖的contentSize。
具體的代碼解析 ,我已經(jīng)寫在了工具類中,十分清晰,每句話幾乎都有注釋,每個(gè)類的創(chuàng)建時(shí)機(jī)、執(zhí)行對(duì)象都有明確的標(biāo)注。