亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS下拉、上拉刷新控件的封裝

2020-07-26 02:20:23
字體:
來源:轉載
供稿:網友

iOS 封裝下拉、上拉刷新控件,首先看下效果圖:

簡單闡述一下:自定義頭部、尾部刷新視圖,繼承UIView,通過KVO監聽scrollView的滑動,通過偏移量設置刷新狀態,通過修改狀態修改scrollView的滾動位置。建一個UIScrollView的分類,添加上拉、下拉刷新及回調的方法,可以讓UITableView、UICollectionView直接調用。現在很多應用是在滑動到底部自動進行上拉加載超做,可以在scrollViewDidScroll這個代理方法中手動調用尾部刷新。

下面貼上主要相關代碼:

控制器ViewController:

#import <UIKit/UIKit.h> @interface ViewController : UIViewController @end /*** ---------------分割線--------------- ***/ #import "ViewController.h"#import "HWRefresh.h" @interface ViewController ()<UITableViewDataSource, UITableViewDelegate> @property (nonatomic, strong) NSMutableArray *array;@property (nonatomic, strong) UITableView *tableView;@property (nonatomic, assign) NSInteger page; @end @implementation ViewController - (NSMutableArray *)array{ if (!_array) {  _array = [NSMutableArray array]; }  return _array;} - (void)viewDidLoad { [super viewDidLoad];  self.view.backgroundColor = [UIColor blackColor]; self.page = 1;  //模擬獲取信息 [self getInfo];  //創建控件 [self creatControl];  //添加頭部刷新 [self addHeaderRefresh];  //添加尾部刷新 [self addFooterRefresh];} - (void)getInfo{ NSArray *array = @[@"iOS HERO博客", @"iOS HERO博客", @"iOS HERO博客", @"iOS HERO博客", @"http://blog.csdn.net/hero_wqb"]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{  if (self.page == 1) {   self.array = [NSMutableArray arrayWithArray:array];  }else{   [self.array addObjectsFromArray:array];  }  [_tableView reloadData];  [_tableView headerEndRefreshing];  [_tableView footerEndRefreshing];  NSLog(@"已經刷新好了"); });} - (void)creatControl{ //列表視圖 _tableView = [[UITableView alloc] initWithFrame:CGRectMake(20, 64, [[UIScreen mainScreen] bounds].size.width - 100, [[UIScreen mainScreen] bounds].size.height - 164) style:UITableViewStylePlain]; _tableView.dataSource = self; _tableView.delegate = self; [self.view addSubview:_tableView];} - (void)addHeaderRefresh{ __weak typeof(self) weakSelf = self; [_tableView addHeaderRefreshWithCallback:^{  __strong typeof(weakSelf) strongSelf = weakSelf;  strongSelf.page = 1;  [strongSelf getInfo]; }];} - (void)addFooterRefresh{ __weak typeof(self) weakSelf = self; [_tableView addFooterRefreshWithCallback:^{  __strong typeof(weakSelf) strongSelf = weakSelf;  strongSelf.page ++;  [strongSelf getInfo]; }];} #pragma mark - UITableViewDataSource- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return self.array.count;} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *identifier = @"refreshTest"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (!cell) {  cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; } cell.textLabel.text = [_array[indexPath.row] stringByAppendingString:[NSString stringWithFormat:@"_%ld", indexPath.row]];  return cell;} - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ //滑動到底部自動刷新 if (_tableView.contentSize.height > _tableView.frame.size.height && _tableView.contentOffset.y + _tableView.frame.size.height > _tableView.contentSize.height - 40 && _page < 50) {  [_tableView footerBeginRefreshing]; }} @end

刷新基類HWRefreshBaseView:

#import <UIKit/UIKit.h> #define HWRefreshContentOffset @"contentOffset" typedef enum { HWRefreshStateNormal = 0, //普通狀態 HWRefreshStatePulling,  //釋放即可刷新的狀態 HWRefreshStateRefreshing, //正在刷新中的狀態} HWRefreshState; @interface HWRefreshBaseView : UIView @property (nonatomic, weak) UIScrollView *scrollView;@property (nonatomic, copy) NSString *pullToRefreshText;@property (nonatomic, copy) NSString *releaseToRefreshText;@property (nonatomic, copy) NSString *refreshingText;@property (nonatomic, copy) void (^refreshingCallback)();@property (nonatomic, assign) HWRefreshState state;@property (nonatomic, assign) UIEdgeInsets scrollViewOriginalInset; - (void)beginRefreshing;- (void)endRefreshing; @end /*** ---------------分割線--------------- ***/ #import "HWRefreshBaseView.h" #define KHWRefreshViewHeight 44.0f#define KImageW 30.0f#define KLabelW 100.0f @interface HWRefreshBaseView () @property (nonatomic, weak) UILabel *rLabel;@property (nonatomic, weak) UIImageView *rImageView; @end @implementation HWRefreshBaseView - (instancetype)initWithFrame:(CGRect)frame{ frame.size.height = KHWRefreshViewHeight; if (self = [super initWithFrame:frame]) {  CGFloat imageH = 30.f;  CGFloat labelH = 20.f;  CGFloat imageX = ([UIScreen mainScreen].bounds.size.width - KImageW - KLabelW) * 0.5;  CGFloat imageY = (KHWRefreshViewHeight - imageH) * 0.5;  CGFloat labelY = (KHWRefreshViewHeight - labelH) * 0.5;    //圖片  UIImageView *rImageView = [[UIImageView alloc] initWithFrame:CGRectMake(imageX, imageY, KImageW, imageH)];  rImageView.image = [UIImage imageNamed:@"refreshing.jpg"];  [self addSubview:rImageView];  self.rImageView = rImageView;    //標簽  UILabel *rLabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMaxX(rImageView.frame), labelY, KLabelW, labelH)];  rLabel.text = self.pullToRefreshText;  rLabel.font = [UIFont systemFontOfSize:14.0f];  rLabel.textAlignment = NSTextAlignmentCenter;  [self addSubview:rLabel];  self.rLabel = rLabel; }  return self;} - (void)willMoveToSuperview:(UIView *)newSuperview{ [super willMoveToSuperview:newSuperview];  //舊的父控件 [self.superview removeObserver:self forKeyPath:HWRefreshContentOffset context:nil];  //新的父控件 if (newSuperview) {  [newSuperview addObserver:self forKeyPath:HWRefreshContentOffset options:NSKeyValueObservingOptionNew context:nil];    //記錄UIScrollView  _scrollView = (UIScrollView *)newSuperview;    //記錄UIScrollView最開始的contentInset  _scrollViewOriginalInset = _scrollView.contentInset; }  //居中顯示圖片、提示信息 CGRect temFrame = _rImageView.frame; temFrame.origin.x = (newSuperview.frame.size.width - KImageW - KLabelW) * 0.5; _rImageView.frame = temFrame;  CGRect tf = _rLabel.frame; tf.origin.x = CGRectGetMaxX(_rImageView.frame); _rLabel.frame = tf;} - (void)setPullToRefreshText:(NSString *)pullToRefreshText{ _pullToRefreshText = pullToRefreshText;  self.rLabel.text = pullToRefreshText;} - (void)setState:(HWRefreshState)state{ if (_state == state) return;  switch (state) {  case HWRefreshStateNormal: {   [self stopAnimating];   self.rLabel.text = self.pullToRefreshText;   break;  }     case HWRefreshStatePulling: {   self.rLabel.text = self.releaseToRefreshText;   break;  }     case HWRefreshStateRefreshing: {   [self startAnimating];   self.rLabel.text = self.refreshingText;   if (self.refreshingCallback) self.refreshingCallback();   break;  }     default:   break; }  _state = state;} //開始刷新- (void)beginRefreshing{ self.state = HWRefreshStateRefreshing;} //結束刷新- (void)endRefreshing{ self.state = HWRefreshStateNormal;} //開始動畫- (void)startAnimating{ NSMutableArray *array = [NSMutableArray array]; for (int i = 0; i < 2; i++) {  NSString *imageName = [NSString stringWithFormat:@"refreshing%02d.jpg", i + 1];  UIImage *image = [UIImage imageNamed:imageName];  [array addObject:image]; }  [_rImageView setAnimationImages:array]; [_rImageView setAnimationDuration:0.3f]; [_rImageView startAnimating];} //結束動畫- (void)stopAnimating{ if (_rImageView.isAnimating) {  [_rImageView stopAnimating];  [_rImageView performSelector:@selector(setAnimationImages:) withObject:nil afterDelay:0]; }} @end

頭部刷新HWRefreshHeader:

#import "HWRefreshBaseView.h" @interface HWRefreshHeader : HWRefreshBaseView + (instancetype)header; @end /*** ---------------分割線--------------- ***/ #import "HWRefreshHeader.h" @implementation HWRefreshHeader + (instancetype)header{ return [[HWRefreshHeader alloc] init];} - (instancetype)initWithFrame:(CGRect)frame{ if (self = [super initWithFrame:frame]) {  self.pullToRefreshText = @"下拉即可刷新";  self.releaseToRefreshText = @"釋放即可刷新";  self.refreshingText = @"刷新中..."; }  return self;} - (void)willMoveToSuperview:(UIView *)newSuperview{ [super willMoveToSuperview:newSuperview];  //設置自己的位置和尺寸 CGRect frame = self.frame; frame.origin.y = - self.frame.size.height; self.frame = frame;}  - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ //不能跟用戶交互或正在刷新就直接返回 if (!self.userInteractionEnabled || self.alpha <= 0.01 || self.hidden || self.state == HWRefreshStateRefreshing) return;  //根據偏移量設置相應狀態 if ([keyPath isEqualToString:HWRefreshContentOffset]) {  [self setStateWithContentOffset]; }} - (void)setStateWithContentOffset{ //當前的contentOffset CGFloat currentOffsetY = self.scrollView.contentOffset.y;  //頭部控件剛好出現的offsetY CGFloat happenOffsetY = - self.scrollViewOriginalInset.top;  //如果是向上滾動到看不見頭部控件,直接返回 if (currentOffsetY >= happenOffsetY) return;  //滑動時 if (self.scrollView.isDragging) {  //普通狀態和即將刷新狀態的臨界點  CGFloat normalTopullingOffsetY = happenOffsetY - self.frame.size.height;    //轉為即將刷新狀態  if (self.state == HWRefreshStateNormal && currentOffsetY < normalTopullingOffsetY) {   self.state = HWRefreshStatePulling;     //轉為普通狀態  }else if (self.state == HWRefreshStatePulling && currentOffsetY >= normalTopullingOffsetY) {   self.state = HWRefreshStateNormal;  }   //松手時,如果是松開就可以進行刷新的狀態,則進行刷新 }else if (self.state == HWRefreshStatePulling) {  self.state = HWRefreshStateRefreshing; }} - (void)setState:(HWRefreshState)state{ //若狀態未改變,直接返回 if (self.state == state) return;  //保存舊狀態 HWRefreshState oldState = self.state;  //調用父類方法 [super setState:state];  switch (state) {  case HWRefreshStateNormal: {   //如果由刷新狀態返回到普通狀態   if (oldState == HWRefreshStateRefreshing) {    [UIView animateWithDuration:0.25f animations:^{     UIEdgeInsets inset = self.scrollView.contentInset;     inset.top -= self.frame.size.height;     self.scrollView.contentInset = inset;    }];   }   break;  }     case HWRefreshStatePulling: {   break;  }     case HWRefreshStateRefreshing: {   //執行動畫   [UIView animateWithDuration:0.25f animations:^{    CGFloat top = self.scrollViewOriginalInset.top + self.frame.size.height;        //增加滾動區域    UIEdgeInsets inset = self.scrollView.contentInset;    inset.top = top;    self.scrollView.contentInset = inset;        //設置滾動位置    CGPoint offset = self.scrollView.contentOffset;    offset.y = - top;    self.scrollView.contentOffset = offset;   }];   break;  }     default:   break; }  self.state = state;} @end

分類UIScrollView+HWRefresh:

#import <UIKit/UIKit.h> @interface UIScrollView (HWRefresh) //添加下拉刷新回調- (void)addHeaderRefreshWithCallback:(void (^)())callback; //讓下拉刷新控件停止刷新- (void)headerEndRefreshing; //添加上拉刷新回調- (void)addFooterRefreshWithCallback:(void (^)())callback; //讓上拉刷新控件開始刷新- (void)footerBeginRefreshing; //讓上拉刷新控件停止刷新- (void)footerEndRefreshing; @end /*** ---------------分割線--------------- ***/ #import "UIScrollView+HWRefresh.h"#import "HWRefreshHeader.h"#import "HWRefreshFooter.h"#import <objc/runtime.h> @interface UIScrollView () @property (nonatomic, weak) HWRefreshHeader *header;@property (weak, nonatomic) HWRefreshFooter *footer; @end @implementation UIScrollView (HWRefresh) static char HWRefreshHeaderKey;static char HWRefreshFooterKey; - (void)setHeader:(HWRefreshHeader *)header{ [self willChangeValueForKey:@"HWRefreshHeaderKey"]; objc_setAssociatedObject(self, &HWRefreshHeaderKey, header, OBJC_ASSOCIATION_ASSIGN); [self didChangeValueForKey:@"HWRefreshHeaderKey"];} - (HWRefreshHeader *)header{ return objc_getAssociatedObject(self, &HWRefreshHeaderKey);} - (void)setFooter:(HWRefreshFooter *)footer{ [self willChangeValueForKey:@"HWRefreshFooterKey"]; objc_setAssociatedObject(self, &HWRefreshFooterKey, footer, OBJC_ASSOCIATION_ASSIGN); [self didChangeValueForKey:@"HWRefreshFooterKey"];} - (HWRefreshFooter *)footer{ return objc_getAssociatedObject(self, &HWRefreshFooterKey);} - (void)addHeaderRefreshWithCallback:(void (^)())callback{ if (!self.header) {  HWRefreshHeader *header = [HWRefreshHeader header];  [self addSubview:header];  self.header = header; }  self.header.refreshingCallback = callback;} - (void)headerEndRefreshing{ [self.header endRefreshing];} - (void)addFooterRefreshWithCallback:(void (^)())callback{ if (!self.footer) {  HWRefreshFooter *footer = [HWRefreshFooter footer];  [self addSubview:footer];  self.footer = footer; }  self.footer.refreshingCallback = callback;} - (void)footerBeginRefreshing{ [self.footer beginRefreshing];} - (void)footerEndRefreshing{ [self.footer endRefreshing];} @end

Demo下載鏈接

寫博客的初心是希望大家共同交流成長,博主水平有限難免有偏頗之處,歡迎批評指正。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
97婷婷大伊香蕉精品视频| 日韩av男人的天堂| 久久久久久一区二区三区| 国产成人精彩在线视频九色| 91亚洲午夜在线| 亚洲成av人乱码色午夜| 在线观看亚洲视频| 欧美视频在线免费| 日韩av在线影视| 成人av番号网| 亚洲va欧美va国产综合久久| 国产精品美女午夜av| 国产精品一区=区| 亚洲欧美一区二区三区情侣bbw| 亚洲精品福利免费在线观看| 国产亚洲人成a一在线v站| 日韩免费电影在线观看| 国产欧美日韩精品专区| 91亚洲精品久久久| 日韩中文字幕网站| 欧美成人精品h版在线观看| 欧美猛少妇色xxxxx| 91国产中文字幕| 日韩一级黄色av| 国产精品678| 精品色蜜蜜精品视频在线观看| 亚洲第一免费网站| 欧美高清电影在线看| 欧洲成人免费aa| 69视频在线播放| 欧美中文字幕视频| 亚洲淫片在线视频| 欧美丰满少妇xxxx| 日韩高清欧美高清| 欧美超级乱淫片喷水| 亚洲一区第一页| 亚洲精品永久免费精品| 国产精品中文在线| 亚洲国产精品小视频| 亚洲欧美精品中文字幕在线| 992tv成人免费视频| 日韩中文字幕免费视频| 成人在线免费观看视视频| 久久影视电视剧凤归四时歌| 国产精品久久久久一区二区| 色综合视频网站| 国产精品白丝av嫩草影院| 欧美性xxxx| 中文亚洲视频在线| 精品国产成人在线| 亚洲天堂男人的天堂| 国产精品吊钟奶在线| 亚洲人成人99网站| 国产一区二区三区在线免费观看| 精品欧美国产一区二区三区| 日韩动漫免费观看电视剧高清| 欧美做爰性生交视频| 中文字幕久热精品在线视频| 欧美一区二区三区免费观看| 中文字幕欧美国内| 韩剧1988在线观看免费完整版| 亚洲精品视频免费| 亚洲精品视频在线观看视频| 另类色图亚洲色图| 456亚洲影院| 91精品国产91| 在线日韩欧美视频| 视频在线观看99| 久久精品91久久香蕉加勒比| 精品久久久免费| 日韩免费观看在线观看| 国产精品成熟老女人| 亚洲直播在线一区| 91久久精品国产91久久| 日韩欧美在线视频免费观看| 日本免费在线精品| 日韩成人激情在线| 在线日韩av观看| 成人在线精品视频| 国产精品手机播放| 日韩理论片久久| 国产精国产精品| 国产精品久久久久久一区二区| 亚洲男人的天堂在线| 国产成人a亚洲精品| 狠狠综合久久av一区二区小说| 日本一区二区三区在线播放| 色婷婷综合久久久久中文字幕1| 在线观看视频亚洲| 亚洲综合中文字幕在线| 国产精品第一区| 中文字幕av一区二区三区谷原希美| 国产亚洲欧美日韩一区二区| 欧美最猛性xxxx| 国产精品国语对白| 久久99热这里只有精品国产| 日韩va亚洲va欧洲va国产| 成人免费视频a| 亚洲国产精品电影在线观看| 亚洲精品久久视频| 91国产精品91| 国产成人免费91av在线| 国产精品第1页| 日韩美女视频免费在线观看| 欧美激情亚洲视频| 欧美激情在线有限公司| 福利视频第一区| 国产日韩在线视频| 久久精品国产电影| 亚洲区中文字幕| 日本在线精品视频| 精品一区二区亚洲| 97视频免费在线看| 黑人精品xxx一区| 国产精品丝袜一区二区三区| 欧美性xxxx在线播放| 福利一区视频在线观看| 国产精品va在线| 国内精品小视频在线观看| 亚洲国产精品免费| 国产精品久久久久久久久久久不卡| 亚洲老板91色精品久久| 欧美视频在线观看 亚洲欧| 国产精品电影观看| 国产亚洲精品高潮| 国产午夜一区二区| 亚洲精品欧美日韩专区| 亚洲欧洲av一区二区| 国产丝袜高跟一区| 亚洲成人精品久久久| 视频一区视频二区国产精品| 亚洲男人的天堂网站| 久久97久久97精品免视看| 欧美日本在线视频中文字字幕| 欧美野外wwwxxx| 欧美第一淫aaasss性| 久久久久国产精品免费网站| 欧美精品videofree1080p| 亚洲欧美制服第一页| 成人字幕网zmw| 成人免费看黄网站| 日本久久中文字幕| 色中色综合影院手机版在线观看| 久久欧美在线电影| 色视频www在线播放国产成人| 国产一区二区丝袜| 亚洲第一天堂无码专区| 国产亚洲精品高潮| 黑人巨大精品欧美一区二区免费| 久久99精品久久久久久青青91| 日韩在线中文视频| 久久亚洲精品成人| 成人女保姆的销魂服务| 91久久精品美女| 午夜精品久久久久久99热| 国产精品9999| 91中文字幕在线| 久久免费在线观看| 成人做爰www免费看视频网站| 日韩av中文在线| 伊人男人综合视频网| 亚洲精品中文字幕有码专区| 日韩日本欧美亚洲| 在线亚洲男人天堂|