本文主要是講講自己在項(xiàng)目中基于 MJRefresh 封裝的一套當(dāng)頁面出現(xiàn)異常情況時給出友好提示頁面 YYLrefresh 的實(shí)現(xiàn)思路。
Github下載地址: YYLrefresh
實(shí)現(xiàn)思路
- 采用低侵入式的 category來實(shí)現(xiàn)。
- category不需要通過增加子類而增加現(xiàn)有類的行為(方法), 且類目中的方法與原始類方法基本沒有區(qū)別。
- 通過 category 可以將龐大一個類的方法進(jìn)行劃分,從而便于代碼的日后的維護(hù)、更新以及提高代碼的閱讀性。
- 采用插座式的設(shè)計(jì)無數(shù)據(jù)、無網(wǎng)絡(luò)、請求出錯頁面方便產(chǎn)品的個性化需求,并且提供默認(rèn)實(shí)現(xiàn)。
具體實(shí)現(xiàn)

代碼目錄.png
下面先來看具體實(shí)現(xiàn)的頭文件UIScrollView+Refresh.h
- 首先定義一個枚舉用來區(qū)分當(dāng)前頁面的類型
typedef enum : NSUInteger {
YYLLoadErrorTypeDefalt,
YYLLoadErrorTypeNoNetwork, //沒有網(wǎng)絡(luò)
YYLLoadErrorTypeRequest, //請求接口 后臺報錯
YYLLoadErrorTypeNoData, //當(dāng)前頁面沒有數(shù)據(jù)
} RELoadErrorType;
- 下面定義的屬性,主要是用來決定用 UIScrollView、UITableView...及其子類實(shí)現(xiàn)的頁面是否顯示下拉刷新,上啦加載功能及其回調(diào) Block。
/**
* 是否顯示表格的頭部刷新
*/
@property(nonatomic, assign) BOOL isShowHeaderRefresh;
/**
* 是否顯示表格的尾部刷新
*/
@property(nonatomic, assign) BOOL isShowFooterRefresh;
/**
* 表格頭部刷新調(diào)用的Block
*/
@property(nonatomic, copy) RERefreshTableViewRefreshingBlock headerRefreshingBlock;
/**
* 表格尾部刷新調(diào)用的Block
*/
@property(nonatomic, copy) RERefreshTableViewRefreshingBlock footerRefreshingBlock;
- 下面屬性主要是用來設(shè)置頁面顯示的類型
/**
* 設(shè)置頁面顯示的類型
*/
@property(nonatomic, assign) RELoadErrorType loadErrorType;
/**
* 數(shù)據(jù)是否全部加載完
*/
@property(nonatomic, assign) BOOL isDataLoaded;
/**
是否第一次加載
*/
@property(nonatomic, assign) BOOL isFirstLoading;
/**
* 停止刷新
*/
- (void)endRefreshing;
- 下面是默認(rèn)的無數(shù)據(jù)、無網(wǎng)絡(luò)、請求出錯頁面提示,可以根據(jù)產(chǎn)品的需求替換成自己實(shí)現(xiàn)的 View。 具體使用見項(xiàng)目中的 Demo 實(shí)現(xiàn)。
/**
* 沒有網(wǎng)絡(luò)時顯示的視圖
*/
@property(nonatomic, strong) UIView *refreshNoNetworkView;
/**
* 訪問出錯時顯示的視圖
*/
@property(nonatomic, strong) UIView *refreshRequestErrorView;
/**
* 沒有數(shù)據(jù)顯示的視圖
*/
@property(nonatomic, strong) UIView *refreshNoDataView;
/**
* 錯誤視圖的tableview容器
*/
@property(nonatomic, strong) UITableView *refreshErrorTableView;
UIScrollView+Refresh.m 具體實(shí)現(xiàn)代碼的詳解:
.m 文件主要是重寫 .h文件中的各個屬性的 get 和 set 方法, 然后借助 objc_setAssociatedObject將屬性關(guān)聯(lián)上對象。具體實(shí)現(xiàn)這里就不一一解釋了。主要來看一下下面這個核心的方法實(shí)現(xiàn):
- (void)setLoadErrorType:(YYLLoadErrorType)loadErrorType {
if (self.refreshNoNetworkView.superview) [self.refreshNoNetworkView removeFromSuperview];
if (self.refreshRequestErrorView.superview) [self.refreshRequestErrorView removeFromSuperview];
if (self.refreshNoDataView.superview) [self.refreshNoDataView removeFromSuperview];
if (loadErrorType == YYLLoadErrorTypeNoNetwork) {
self.isShowFooterRefresh = NO;
[self addSubview:self.refreshNoNetworkView];
[self.refreshNoNetworkView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(0);
make.width.mas_equalTo(self.mas_width);
make.top.mas_equalTo(0);
make.height.mas_equalTo(self.mas_height);
}];
} else if (loadErrorType == YYLLoadErrorTypeRequest) {
self.isShowFooterRefresh = NO;
[self addSubview:self.refreshRequestErrorView];
[self.refreshRequestErrorView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(0);
make.width.mas_equalTo(self.mas_width);
make.top.mas_equalTo(0);
make.height.mas_equalTo(self.mas_height);
}];
} else if (loadErrorType == YYLLoadErrorTypeNoData) {
self.isShowFooterRefresh = NO;
[self addSubview:self.refreshNoDataView];
[self.refreshNoDataView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(0);
make.width.mas_equalTo(self.mas_width);
make.top.mas_equalTo(0);
make.height.mas_equalTo(self.mas_height);
}];
}
objc_setAssociatedObject(self, &loadErrorTypeKey, @(loadErrorType), OBJC_ASSOCIATION_ASSIGN);
[self endRefreshing];
}
這個方法主要是通過用戶設(shè)置的類型 loadErrorType 來決定該怎樣顯示頁面: 具體實(shí)現(xiàn)是將原來的頁面上顯示的輔助視圖移除掉,根據(jù)類型顯示新的視圖。新視圖的位置大小與頁面相同。