您的位置:首页 > 产品设计 > UI/UE

iOS 自定义刷新控件UIScrollView (Refresh)

2016-01-30 17:43 796 查看
开发的时候经常会用到下拉刷新这个控件,一直以来想自己写一个,但是时间问题,都是使用别人写好的,

今天查了资料,自己自定一个

1.主要原理:

       a.创建UIScrollView的类目 提供 类似addHeaderRefresh等方法,这样tableview collectview等他们都是集成UIScrollView,所以可以直接条用类目提供的方法,(很多第三方基本都是这么干) 一般上拉 下拉都是捕获scrollview的偏移(contentoffset),但是在UIScrollview的类目里面如果捕获这个东西呢?我一开始是想通过类目里面自己实现scrollview的delegate,根据-
(void)scrollViewDidScroll:(UIScrollView
*)scrollView;   获取contentoffset,但是这样设计违背了设计理念:作为插件而言。就破坏了别人原本的逻辑。比如别人也需要监听这些行为。可能互相覆盖什么的。所以采用KVO的方式兼听属性contentoffset的变化
就很好的解决了这一点

        b.再创建一个自定义的展示样式CustomRefreshView,这个view里面根据scrollview的偏移配置对应的UI展示 (捕获到“正在刷新”的状态的时候 利用外部传进来的刷新方法:SEL 和 执行方法的目标target 执行[self.actionTargetperformSelector:self.actionwithObject:nilafterDelay:0];



2.只是储备,类目的相关知识  对象关联等

直接上代码:(UIScrollView+Refresh).h

//
//  UIScrollView+Refresh.h
//  SearchVCDemo
//
//  Created by Programmer two on 16/1/30.
//  Copyright © 2016年 linpeng. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "CustomRefreshView.h"

@interface UIScrollView (Refresh)
@property (nonatomic,strong) CustomRefreshView *topShowView;

-(void)addHeaderRefreshWithTarget:(id)target action:(SEL)action;

-(void)beginHeaderRefresh;
-(void)endHeaderRefresh;

@end


.m

//
//  UIScrollView+Refresh.m
//  SearchVCDemo
//
//  Created by Programmer two on 16/1/30.
//  Copyright © 2016年 linpeng. All rights reserved.
//

#import "UIScrollView+Refresh.h"
#import <objc/runtime.h>
#define kObservePath        @"contentOffset"

@implementation UIScrollView (Refresh)

static char topShowViewKey;

-(void)addHeaderRefreshWithTarget:(id)target action:(SEL)action
{
if (!self.topShowView)
{
self.topShowView = [[CustomRefreshView alloc] init];
}
self.topShowView.frame = CGRectMake(0, -100, self.frame.size.width, 100);
self.topShowView.parentView = self;
self.topShowView.actionTarget = target;
self.topShowView.action = action;
[self addSubview:self.topShowView];
//兼听滚动便宜
[self addObserver:self forKeyPath:kObservePath options:NSKeyValueObservingOptionNew context:nil];
}

-(void)beginHeaderRefresh
{
[self.topShowView beginHeaderRefresh];
}
-(void)endHeaderRefresh
{
[self.topShowView endHeaderRefresh];
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
if ([kObservePath isEqualToString:keyPath])
{
NSValue *point = (NSValue *)[change objectForKey:@"new"];
CGPoint p = [point CGPointValue];
[self.topShowView adjustY:-p.y];
}

}
-(CustomRefreshView *)topShowView
{
return objc_getAssociatedObject(self, &topShowViewKey);
}

-(void)setTopShowView:(CustomRefreshView *)topShowView
{
objc_setAssociatedObject(self, &topShowViewKey, topShowView, OBJC_ASSOCIATION_RETAIN);
}

-(void)dealloc
{
if (self.topShowView)//注册过刷新的必须要除移开监听
{
[self removeObserver:self forKeyPath:kObservePath context:kObserveContent];
}
}

@end

自定义展示的UI视图:

CustomRefreshView.h

//
//  CustomRefreshView.h
//  SearchVCDemo
//
//  Created by Programmer two on 16/1/30.
//  Copyright © 2016年 linpeng. All rights reserved.
//

#import <UIKit/UIKit.h>

typedef NS_ENUM(NSUInteger,RefreshStatus)
{
RefreshStatus_Normal = 1,
RefreshStatus_BeginRefresh,
RefreshStatus_Refreshing,
};

@interface CustomRefreshView : UIView

@property (nonatomic,strong)UILabel *updateLabel;
@property (nonatomic,weak) id actionTarget;
@property (nonatomic)SEL action;
@property (nonatomic,strong) UIScrollView *parentView;
@property (nonatomic) RefreshStatus refreshStatus;

-(void)beginHeaderRefresh;
-(void)endHeaderRefresh;

-(void)adjustY:(CGFloat)y;

@end


.m

//
//  CustomRefreshView.m
//  SearchVCDemo
//
//  Created by Programmer two on 16/1/30.
//  Copyright © 2016年 linpeng. All rights reserved.
//

#import "CustomRefreshView.h"
#define kMinOffSetY     100

@implementation CustomRefreshView

-(instancetype)init
{
if (self = [super init])
{
[self addSubview:self.updateLabel];
self.refreshStatus = RefreshStatus_Normal;
}
return self;
}

-(void)layoutSubviews
{
self.updateLabel.frame = CGRectMake(0, self.frame.size.height - 20, self.frame.size.width, 20);
}
-(void)beginHeaderRefresh
{
self.refreshStatus = RefreshStatus_Refreshing;
}
-(void)endHeaderRefresh
{
[self isAdjustToNormal:YES];
self.refreshStatus = RefreshStatus_Normal;

}

-(void)adjustY:(CGFloat)y
{
if (self.parentView.isDragging)
{
if (y>kMinOffSetY)
{
self.refreshStatus = RefreshStatus_BeginRefresh;
}
else
{
self.refreshStatus = RefreshStatus_Normal;
}
}
else
{
if (y>kMinOffSetY)
{
self.refreshStatus = RefreshStatus_Refreshing;
}
}
}

-(void)isAdjustToNormal:(BOOL)normal
{
CGFloat y = 0;
if (!normal)
{
y = 50;
}
__weak CustomRefreshView *weakSelf = self;
[UIView animateWithDuration:0.5 animations:^{
weakSelf.parentView.contentInset = UIEdgeInsetsMake(y, 0, 0, 0);
}];
}
-(void)doNormalRefresh
{
self.updateLabel.text = @"下拉刷新....";
}
-(void)doBeginRefresh
{
self.updateLabel.text = @"释放加载....";
}
-(void)doRefreshing
{
self.updateLabel.text = @"正在努力加载...";
[self isAdjustToNormal:NO];
[self.actionTarget performSelector:self.action withObject:nil afterDelay:0];
}

-(void)setRefreshStatus:(RefreshStatus)refreshStatus
{
if(_refreshStatus == refreshStatus)
return;

switch (refreshStatus)
{
case RefreshStatus_Normal:
[self doNormalRefresh];
break;
case RefreshStatus_BeginRefresh:
{
[self doBeginRefresh];
break;
}
case RefreshStatus_Refreshing:
{
[self doRefreshing];
break;
}
default:
break;
}
_refreshStatus = refreshStatus;
}

-(UILabel *)updateLabel
{
if (_updateLabel == nil)
{
_updateLabel = [[UILabel alloc] init];
_updateLabel.textAlignment = NSTextAlignmentCenter;
_updateLabel.font = [UIFont systemFontOfSize:13];
_updateLabel.textColor = [UIColor grayColor];
}
return _updateLabel;
}

@end


一个简单的下拉刷新就这么完成了,使用也很简单:

[self.tableViewaddHeaderRefreshWithTarget:selfaction:@selector(doLoadData)];
-(void)doLoadData
{
__weak ViewController1 *weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[weakSelf.tableView endHeaderRefresh];
});
}


以下这两个方法都是直接对UI的操作 独立开来

[self.tableViewbeginHeaderRefresh];

[self.tableViewendHeaderRefresh];

看一下效果吧:







(Gifrocket 制作gif)

大体的样式完成了 接下来就可以根据自己的喜好自定义这个

CustomRefreshView,做一些酷炫的效果!
我的实现方式思路是参考这篇文章:http://blog.csdn.net/x6587305x/article/details/42640291
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: