iOS筆記-(利用EGORefreshTableHeaderView自定義上拉載入和下拉重新整理)
阿新 • • 發佈:2019-01-22
</pre><p class="p1"></p><pre name="code" class="objc">GIthub下載一個DEMO,在RootviewController中檢視. UIScrollViewDelegate:是監聽滑動的距離 EGORefreshTableHeaderDelegate:是頭部控制元件的代理方法. //1.下拉到一定距離,手指放開會觸發: (void)egoRefreshTableHeaderDidTriggerRefresh:(EGORefreshTableHeaderView*)view{ } //2.資料載入完畢後,停止載入,檢視彈回原來位置, - (void)doneLoadingTableViewData{ } // 親手示範,建立工程 //1. 建立一個基本的BaseTableview,帶有下拉重新整理功能. BaseTableview繼承UITableView. //2. 匯入EGOTablePullRefresh資料夾到工程中. #import “EGORefreshTableHeaderView.h" //3. 私有變數 EGORefreshTableHeaderView *_refreshHeaderView;//頭部控制元件 //4.不是所有的TableView都要下拉重新整理功能,此時新增 @property (nonatomic,assign) BOOL refreshHeader;//是否需要下拉效果 //5.在這裡新增頭部控制元件 //5-1 /*方法一 *用XIB建立 */ - (void)awakeFromNib{ [self initHeaderView]; } /* 方法二 * 用程式碼建立 */ - (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style{ self = [super initWithFrame:frame style:style]; if (self) { [self initHeaderView]; } return self; } //5-2 //開啟下拉效果 self.refreshHeader = YES; //重寫下拉布爾型值 - (void)setRefreshHeader:(BOOL)refreshHeader{ _refreshHeader = refreshHeader; if (_refreshHeader) { //開啟下拉效果,新增頭部控制元件 [self addSubview:_refreshHeaderView]; }else{ //關閉下拉效果,移除頭部控制元件 if ([_refreshHeaderView superview]) { [_refreshHeaderView removeFromSuperview]; } } } //6.新增EGO代理方法.. #pragma mark - #pragma mark Data Source Loading / Reloading Methods - (void)reloadTableViewDataSource{ _reloading = YES; } - (void)doneLoadingTableViewData{ _reloading = NO; [_refreshHeaderView egoRefreshScrollViewDataSourceDidFinishedLoading:self]; } #pragma mark - #pragma mark UIScrollViewDelegate Methods - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ [_refreshHeaderView egoRefreshScrollViewDidScroll:scrollView]; } - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ [_refreshHeaderView egoRefreshScrollViewDidEndDragging:scrollView]; } #pragma mark - #pragma mark EGORefreshTableHeaderDelegate Methods - (void)egoRefreshTableHeaderDidTriggerRefresh:(EGORefreshTableHeaderView*)view{ [self reloadTableViewDataSource]; [self performSelector:@selector(doneLoadingTableViewData) withObject:nil afterDelay:3.0]; } - (BOOL)egoRefreshTableHeaderDataSourceIsLoading:(EGORefreshTableHeaderView*)view{ return _reloading; } - (NSDate*)egoRefreshTableHeaderDataSourceLastUpdated:(EGORefreshTableHeaderView*)view{ return [NSDate date]; } //下拉,當手指放開時候,呼叫egoRefreshTableHeaderDidTriggerRefresh方法,此時 BaseTableView和控制器要進行通訊,BaseTableView通知控制器此時請求網路資料.(把自己self,路徑indexPath傳出去) 通訊方式用:通知,Block,Delegate. 在這我用Delegate.delegate方法並不一定會實現 所有判斷一下.因為是可選的 if([self.baseDelegate respondsToSelector:@selector(pullDownWithTableView:)]){ [self.baseDelegate pullDownWithTableView:self]; } //注意:因為BaseTableView繼承UITableView, 而且 BaseTableView遵守了UITableViewDelegate,UITableViewDataSource,所以在控制器中 不用遵守UITableViewDelegate,UITableViewDataSource. 在控制器中,當下拉載入完資料後,控制器做的事情是彈回原來位置. //7.增加上拉控制元件 上拉控制元件可以放在taleView的尾部檢視. //BaseTableView有個資料來源,陣列data.先判斷data是否有資料,無資料將尾部檢視隱藏;然後再判斷有資料時候,是否最後一頁.是最後一頁,”已載入全部資料”. //點選尾部檢視”檢視更多”,載入資料時,尾部檢視變位”正在載入”.當載入完畢,尾部檢視變為原樣”檢視更多”. //當載入到最後一頁,尾部檢視顯示為:“已載入全部資料” //在控制器中,呼叫BaseTableView的reloadData時,複寫reloadData方法,讓控制器尾部檢視上拉載入完畢後停止風火輪的轉動. //除了點選”檢視更多”按鈕能實現上拉載入,還可以設定當手指停止拖拽的時候,判斷scrollview的偏移量是否滿足 上拉載入. (1)float offset = scrollView.contentOffset.y; (2)float contentHeight = scrollView.contentSize.height; (3)//當滑動到尾部檢視”檢視更多”,差值就是scrollView的高度 float sub = contentHeight - offset; if(sub - scrollView.bounds.size.height > 30){ }
</pre><pre name="code" class="objc">以下是原始碼,繼承BaseTableView,可以做更多有趣的上下拉載入資料效果... <pre name="code" class="objc">// // BaseTableView.h // DEMOForEGOTalbeViewPullRefresh // // Created by kun on 15/8/1. // Copyright (c) 2015年 kun. All rights reserved. // #import <UIKit/UIKit.h> #import "EGORefreshTableHeaderView.h" /** * 定製協議,BaseTableView通知控制器去請求資料 */ @class BaseTableView; @protocol BaseTableViewDelegate <NSObject> @optional - (void)pullDownWithTableView:(BaseTableView *)baseTableView;//下拉重新整理 - (void)pullUpWithTableView:(BaseTableView *)baseTableView; //上拉載入 - (void)baseTableView:(BaseTableView *)baseTableView didselectRowAtIndexPath:(NSIndexPath *)indexPath;//選中某一行 @end @interface BaseTableView : UITableView<EGORefreshTableHeaderDelegate,UITableViewDelegate,UITableViewDataSource>{ /** * 手動新增以下私有變數 * 上拉控制元件 */ EGORefreshTableHeaderView *_refreshHeaderView;//頭部控制元件 BOOL _reloading;//是否正在載入 /** * 下拉控制元件 */ UIButton *_btnPullUp; UIActivityIndicatorView *_acitivityView; } @property (nonatomic,assign) BOOL refreshHeader;//是否需要下拉效果 @property (nonatomic,strong) NSArray *data;//為tableView提供資料 @property (nonatomic,weak) id <BaseTableViewDelegate>baseDelegate; /** * 上拉載入完全部資料的標記 */ @property (nonatomic,assign) BOOL isPullUpAllFinish; /** * 資料載入完畢後,停止載入,檢視彈回原來位置 */ - (void)doneLoadingTableViewData; /** * 停止上拉載入 */ - (void)stopPullUpLoadMore; @end
</pre><pre name="code" class="objc">
</pre><pre name="code" class="objc">// // BaseTableView.m // DEMOForEGOTalbeViewPullRefresh // // Created by kun on 15/8/1. // Copyright (c) 2015年 kun. All rights reserved. // #import "BaseTableView.h" @implementation BaseTableView /*方法一 *用XIB建立 */ - (void)awakeFromNib{ //初始化下拉檢視 [self initHeaderView]; //初始化尾部控制元件 [self initFooterView]; } /* 方法二 * 用程式碼建立 */ - (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style{ self = [super initWithFrame:frame style:style]; if (self) { //初始化下拉檢視 [self initHeaderView]; //初始化尾部控制元件 [self initFooterView]; } return self; } #pragma mark - init //初始化頭部控制元件 - (void)initHeaderView{ //1.設定頭部控制元件 _refreshHeaderView = [[EGORefreshTableHeaderView alloc] initWithFrame:CGRectMake(0.0f, 0.0f - self.bounds.size.height, self.frame.size.width, self.bounds.size.height)]; _refreshHeaderView.delegate = self; _refreshHeaderView.backgroundColor = [UIColor clearColor]; //2.開啟下拉效果 self.refreshHeader = YES; //3.新增tableView代理物件為BaseTableView self.dataSource = self; self.delegate = self; } //初始化尾部控制元件 - (void)initFooterView{ /** * 先建立"檢視更多"按鈕,當點選"檢視更多"按鈕,上拉資料,同時出現風火輪 */ //1. _btnPullUp = [UIButton buttonWithType:UIButtonTypeRoundedRect]; _btnPullUp.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44); _btnPullUp.backgroundColor = [UIColor clearColor]; [_btnPullUp setTitle:@"檢視更多" forState:UIControlStateNormal]; [_btnPullUp addTarget:self action:@selector(pullUpToLoadMore) forControlEvents:UIControlEventTouchUpInside]; self.tableFooterView = _btnPullUp; //2.風火輪設定 UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; activityView.frame = CGRectMake(100, 10, 20, 20); [activityView stopAnimating];//初始化時停止旋轉。 [_btnPullUp addSubview:activityView]; _acitivityView = activityView; } //重寫下拉布爾型值 - (void)setRefreshHeader:(BOOL)refreshHeader{ _refreshHeader = refreshHeader; if (_refreshHeader) { //開啟下拉效果,新增頭部控制元件 [self addSubview:_refreshHeaderView]; }else{ //關閉下拉效果,移除頭部控制元件 if ([_refreshHeaderView superview]) { [_refreshHeaderView removeFromSuperview]; } } } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ #pragma mark - Action //上拉載入更多 - (void)pullUpToLoadMore{ //1.判斷代理方法是否執行 if ([self.baseDelegate respondsToSelector:@selector(pullUpWithTableView:)]) { //1-1 [self.baseDelegate pullUpWithTableView:self]; //1-2.尾部檢視相應變化 [self startPullUpLoadMore]; } } #pragma mark - UITableViewDelegate //(子類可以覆蓋父類的代理方法) - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return self.data.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ if ([self.baseDelegate respondsToSelector:@selector(baseTableView:didselectRowAtIndexPath:)]) { [self.baseDelegate baseTableView:self didselectRowAtIndexPath:indexPath]; } } - (void)reloadData{ [super reloadData]; //停止上拉載入更多 [self stopPullUpLoadMore]; } #pragma mark - #pragma mark Data Source Loading / Reloading Methods - (void)reloadTableViewDataSource{ _reloading = YES; } //2.資料載入完畢後,停止載入,檢視彈回原來位置, - (void)doneLoadingTableViewData{ _reloading = NO; [_refreshHeaderView egoRefreshScrollViewDataSourceDidFinishedLoading:self]; } #pragma mark - #pragma mark UIScrollViewDelegate Methods - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ [_refreshHeaderView egoRefreshScrollViewDidScroll:scrollView]; } //當手指停止拖拽的時候呼叫. - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ [_refreshHeaderView egoRefreshScrollViewDidEndDragging:scrollView]; //1.判斷是否到最後一頁 if(!self.isPullUpAllFinish){ return; } //2. float offset = scrollView.contentOffset.y; float contentHeight = scrollView.contentSize.height; //當滑動到尾部檢視"檢視更多",差值就是scrollView的高度 float sub = contentHeight - offset; if(scrollView.bounds.size.height - sub> 30){ //2-1.控制狀態發生變化 [self startPullUpLoadMore]; //2-2.通知控制器,上拉載入更多 if ([self.baseDelegate respondsToSelector:@selector(pullUpWithTableView:)]) { [self.baseDelegate pullUpWithTableView:self]; } } } #pragma mark - #pragma mark EGORefreshTableHeaderDelegate Methods //1.下拉到一定距離,手指放開會觸發: - (void)egoRefreshTableHeaderDidTriggerRefresh:(EGORefreshTableHeaderView*)view{ //1.設定為正在載入狀態 [self reloadTableViewDataSource]; //2.停止載入,彈回原來位置 //2-1 除錯用 // [self performSelector:@selector(doneLoadingTableViewData) withObject:nil afterDelay:3.0]; //2-2 與控制器進行通訊 if([self.baseDelegate respondsToSelector:@selector(pullDownWithTableView:)]){ [self.baseDelegate pullDownWithTableView:self]; } } - (BOOL)egoRefreshTableHeaderDataSourceIsLoading:(EGORefreshTableHeaderView*)view{ return _reloading; } - (NSDate*)egoRefreshTableHeaderDataSourceLastUpdated:(EGORefreshTableHeaderView*)view{ return [NSDate date]; } #pragma mark - Private /** * 開始上拉載入 */ - (void)startPullUpLoadMore{ //1.文字發生變化 _btnPullUp.enabled = NO; [_btnPullUp setTitle:@"正在載入..." forState:UIControlStateNormal]; //2.風火輪轉動 [_acitivityView startAnimating]; } /** * 停止上拉載入 */ - (void)stopPullUpLoadMore{ //判斷是否有資料 if (self.data.count > 0) { //0.顯示 _btnPullUp.hidden = NO; //1.文字恢復原樣 _btnPullUp.enabled = YES; [_btnPullUp setTitle:@"檢視更多" forState:UIControlStateNormal]; //2.風火輪停止轉動 [_acitivityView stopAnimating]; //3.判斷是否最後一頁 if(!self.isPullUpAllFinish){ [_btnPullUp setTitle:@"已載入全部資料" forState:UIControlStateNormal]; _btnPullUp.enabled = NO; } }else{ _btnPullUp.hidden = YES; } } @end