iOS 自定义下拉刷新控件 —— 解决图片拉伸与数据刷新冲突
dysg0896
7年前
<p>前言</p> <p>iOS 的下拉刷新用的最广泛的应该是 <a href="/misc/goto?guid=4959756585464737515" rel="nofollow,noindex">MJRefresh</a> . 但是有时候不能满足我们的特殊需求. 如下拉时候, 设置的图片放大, 那么用该控件刷新就会有些问题. 今天作者 就简单封装一个 刷新控件, 仅为各位提供个思路.</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/d86080d55226e424be532930d7f22527.gif"></p> <p>效果.gif</p> <p>一. 控件</p> <p>RefreshView.h文件</p> <pre> <code class="language-objectivec">#import <uikit uikit="" h=""> typedef NS_ENUM(NSInteger, RefreshViewStyle) { RefreshViewStyleNormal, // 普通状态 RefreshViewStylePulling, // 超过临界点 RefreshViewStyleLoad // 正在刷新 }; @interface RefreshView : UIView /** 刷新控件状态 */ @property (nonatomic, assign) RefreshViewStyle refreshStyle; /** 状态变化临界值 */ @property (nonatomic, assign) CGFloat refreshOffset; /** 开始 */ -(void)startAnimation:(void(^)(void))start; /** 移除 */ -(void)removeAnimation; /** 刷新控件设置 @param scrollY 下拉值 @param isDragging 是否正在拖拽 @param load 加载刷新 */ -(void)contentOffsetY:(CGFloat)scrollY withDragging:(BOOL)isDragging isStyleLoad:(void(^)(void))load; @end </uikit></code></pre> <p>RefreshView.m文件</p> <pre> <code class="language-objectivec">#import "RefreshView.h" #define kWidth [UIScreen mainScreen].bounds.size.width @interface RefreshView () /** 图形变化 */ @property (nonatomic, strong) UIImageView *imgView; /** 设置加载位置 */ @property (nonatomic, assign) CGRect loadFrame; @end @implementation RefreshView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.loadFrame = frame; self.imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)]; self.imgView.contentMode = UIViewContentModeScaleAspectFit; self.imgView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; [self addSubview:self.imgView]; } return self; } -(void)setRefreshStyle:(RefreshViewStyle)refreshStyle{ if (_refreshStyle != refreshStyle) { _refreshStyle = refreshStyle; } // 根据控件状态 设置图片 switch (refreshStyle) { case RefreshViewStyleNormal: { self.imgView.image = [UIImage imageNamed:@"arrow.png"]; [UIView animateWithDuration:0.2 animations:^{ self.imgView.transform = CGAffineTransformIdentity; }]; } break; case RefreshViewStylePulling: { self.imgView.image = [UIImage imageNamed:@"arrow.png"]; [UIView animateWithDuration:0.2 animations:^{ self.imgView.transform = CGAffineTransformMakeRotation(M_PI); }]; } break; case RefreshViewStyleLoad: { self.imgView.image = [UIImage imageNamed:@"quan.png"]; } break; } } /** 开始 */ -(void)startAnimation:(void(^)(void))start{ if (![self.imgView.layer.animationKeys containsObject:@"rotationAnimation"]) { CABasicAnimation* rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; rotationAnimation.fromValue = [NSNumber numberWithInt:0]; rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2.0 ]; rotationAnimation.duration = 0.7; rotationAnimation.repeatCount = HUGE_VALF; rotationAnimation.cumulative = YES; // 切换界面 animationKeys 清空了 需要设置removedOnCompletion = NO; rotationAnimation.removedOnCompletion = NO; rotationAnimation.fillMode = kCAFillModeForwards; [self.imgView.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"]; start(); } } /** 移除 */ -(void)removeAnimation{ if ([self.imgView.layer.animationKeys containsObject:@"rotationAnimation"]) { [UIView animateWithDuration:0.7 animations:^{ self.alpha = 0; } completion:^(BOOL finished) { self.frame = CGRectMake((kWidth - self.loadFrame.size.width) / 2, -self.loadFrame.size.height, self.loadFrame.size.width, self.loadFrame.size.height); self.alpha = 1; // 手动释放 [self.imgView.layer removeAnimationForKey:@"rotationAnimation"]; self.refreshStyle = RefreshViewStyleNormal; }]; } } //3 刷新控件设置 -(void)contentOffsetY:(CGFloat)scrollY withDragging:(BOOL)isDragging isStyleLoad:(void(^)(void))load{ // 3.0 如何不是下拉操作 直接返回 if (scrollY < 0) { return; } // 3.1 除正在刷新, 其余情况 高度跟随变化 if (self.refreshStyle != RefreshViewStyleLoad) { self.frame = CGRectMake(self.loadFrame.origin.x, scrollY - self.loadFrame.size.height, self.loadFrame.size.width, self.loadFrame.size.height); } if (isDragging) { // 3.2 正在拉拽 if (scrollY >= self.refreshOffset && self.refreshStyle == RefreshViewStyleNormal) { // 拉拽超过临界点, 修改状态为[临界拉拽] self.refreshStyle = RefreshViewStylePulling; }else if (scrollY < self.refreshOffset && self.refreshStyle == RefreshViewStylePulling){ // 拉拽小于临界点, 修改状态为[正常] self.refreshStyle = RefreshViewStyleNormal; } } else { // 3.3 未处于拉拽状态, 并且状态为[临界拉拽] if (self.refreshStyle == RefreshViewStylePulling) { self.refreshStyle = RefreshViewStyleLoad; [UIView animateWithDuration:0.2 animations:^{ self.frame = self.loadFrame; }]; // 刷新界面 [self startAnimation:^{ load(); }]; } } } @end</code></pre> <p>二. 使用</p> <pre> <code class="language-objectivec">#import "ViewController.h" #import "RefreshView.h" #define kWidth [UIScreen mainScreen].bounds.size.width #define kHeight [UIScreen mainScreen].bounds.size.height static CGFloat HeaderViewHegiht = 150.0; @interface ViewController () <uitableviewdelegate uitableviewdatasource=""> @property (nonatomic, strong) UITableView *tableView; @property (nonatomic, strong) UIImageView *headerView; // 刷新控件 @property (nonatomic, strong) RefreshView *refreshView; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor blackColor]; // 0.1 创建TableView self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, kWidth, [UIScreen mainScreen].bounds.size.height) style:UITableViewStylePlain]; self.tableView.delegate = self; self.tableView.dataSource = self; [self.view addSubview:self.tableView]; self.tableView.rowHeight = 50; if (@available(iOS 11.0, *)) { self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; } // 0.2 向下偏移150 self.tableView.contentInset = UIEdgeInsetsMake(HeaderViewHegiht, 0, 0, 0); // 0.3 添加顶部视图 self.headerView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -HeaderViewHegiht, kWidth, HeaderViewHegiht)]; self.headerView.image = [UIImage imageNamed:@"huanghun.jpg"]; self.headerView.contentMode = UIViewContentModeScaleAspectFill; [self.tableView addSubview:self.headerView]; [self creatRefreshView]; } #pragma mark - 刷新控件 -(void)creatRefreshView{ self.refreshView = [[RefreshView alloc] initWithFrame:CGRectMake((kWidth - 30) /2, 40, 30, 30)]; [self.view insertSubview:self.refreshView aboveSubview:self.tableView]; self.refreshView.refreshStyle = RefreshViewStyleLoad; self.refreshView.refreshOffset = 130.0; __weak typeof(self)weakSelf = self; [self.refreshView startAnimation:^{ [weakSelf handleData]; }]; } - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ //1 头部背景图拉伸形变 if (scrollView.contentOffset.y < - HeaderViewHegiht) { CGRect newHeaderFrame = self.headerView.frame; newHeaderFrame.origin.y = scrollView.contentOffset.y; newHeaderFrame.size.height = - scrollView.contentOffset.y; self.headerView.frame = newHeaderFrame; } //2 刷新控件设置 __weak typeof(self)weakSelf = self; CGFloat refreshOffsetY = -scrollView.contentOffset.y - HeaderViewHegiht; [self.refreshView contentOffsetY:refreshOffsetY withDragging:scrollView.isDragging isStyleLoad:^{ [weakSelf handleData]; }]; } -(void)handleData{ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.refreshView removeAnimation]; }); } -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return 30; } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *identifier = @"identifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier]; } cell.textLabel.text = [NSString stringWithFormat:@"%ld", (long)indexPath.row]; return cell; } @end </uitableviewdelegate></code></pre> <p>以上 !</p> <p>作者:Mr_Lucifer</p> <p>链接:https://www.jianshu.com/p/1e9638b4e8b1</p> <p> </p> <p>来自:http://www.cocoachina.com/ios/20180123/21940.html</p> <p> </p>