前言
iOS 的下拉刷新用的最广泛的应该是 MJRefresh. 但是有时候不能满足我们的特殊需求. 如下拉时候, 设置的图片放大, 那么用该控件刷新就会有些问题. 今天作者 就简单封装一个 刷新控件, 仅为各位提供个思路.

效果.gif
一. 控件
RefreshView.h文件
#importtypedef 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
RefreshView.m文件
#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二. 使用
#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 ()@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
以上 !
作者:Mr_Lucifer
链接:https://www.jianshu.com/p/1e9638b4e8b1