說到下拉刷新我想都會想到MJRefresh,雖然它很強大,但是有些需求還是辦不到,只能自定義.如下圖:
下拉2.gif
MJRefresh是將動畫圖片放在scrollview的頂部,使動畫圖片與scrollview在同一級,并且隨著scrollview的滑動而滑動.而上圖中的效果是將動畫放在視圖控制器上,并且在tableview上面,而且根據(jù)tableview滑動改變透明度.
我的思路大概是這樣的:
1.這個自定義的View能隨著scrollview滑動而改變自身的狀態(tài),并且它的X需要在scrollview的中間,Y在scrollview下面一點那么說明View需要持有scrollview,.
2.在View里面監(jiān)聽ScrollView的contentOffset屬性,來做相應(yīng)的處理.
3.刷新狀態(tài)大致分為閑置狀態(tài),正在刷新和結(jié)束刷新3種.
4.正在刷新的時候需要改變scrollView的contentInset,并在刷新結(jié)束后恢復(fù).
好了,沿著這個思路開干吧,代碼量非常少,只有一個文件.
MHRefreshHeader.h
#import <UIKit/UIKit.h>
UIKIT_EXTERN NSString *const BaseRefreshViewObserveKeyPath;
typedef enum {
MHRefreshStateNormal,//閑置狀態(tài)
MHRefreshStateRefreshing,//正在刷新
MHRefreshStateEndRresh,//結(jié)束刷新
} MHRefreshViewState;
@interface MHRefreshHeader : UIView
@property (nonatomic, copy) void(^refreshingBlock)(void);
@property(nonatomic,strong) UIImageView *refreshImageView;
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, assign) MHRefreshViewState refreshState;
- (void)endRefreshing;
+(instancetype)refreshWithScroll:(UIScrollView *)scrollView;
@end
MHRefreshHeader.m
#import "MHRefreshHeader.h"
#import "UIView+Additions.h"
static const CGFloat RefreshMinY = - 64.f;
NSString *const BaseRefreshViewObserveKeyPath = @"contentOffset";
@implementation MHRefreshHeader
//使點擊穿透
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
return nil;
}
+(instancetype)refreshWithScroll:(UIScrollView *)scrollView
{
MHRefreshHeader *header = [MHRefreshHeader new];
header.centerX = scrollView.centerX;
header.y = scrollView.y;
header.scrollView = scrollView;
[scrollView.superview addSubview:header];
return header;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self setupView];
}
return self;
}
- (void)setScrollView:(UIScrollView *)scrollView
{
_scrollView = scrollView;
//添加監(jiān)聽
[scrollView addObserver:self forKeyPath:BaseRefreshViewObserveKeyPath options:NSKeyValueObservingOptionNew context:nil];
}
- (void)willMoveToSuperview:(UIView *)newSuperview
{
if (!newSuperview) {
[self.scrollView removeObserver:self forKeyPath:BaseRefreshViewObserveKeyPath];
}
}
-(void)endRefreshing
{
self.refreshState = MHRefreshStateEndRresh;
}
//初始化圖片
- (void)setupView
{
self.backgroundColor = [UIColor clearColor];
_refreshImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"loading_1"]];
NSMutableArray *refreshingImages = [NSMutableArray array];
for (NSUInteger i = 1; i < 6; i++) {
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"loading_%zd", i]];
[refreshingImages addObject:image];
}
_refreshImageView.animationImages = refreshingImages;
self.bounds = _refreshImageView.bounds;
[self addSubview:_refreshImageView];
_refreshImageView.alpha = 0;
self.refreshState = MHRefreshStateNormal;
}
//刷新狀態(tài)改變
- (void)setRefreshState:(MHRefreshViewState)refreshState
{
if (refreshState == MHRefreshStateRefreshing) {
if (self.refreshingBlock) {
self.refreshingBlock();
}
[_refreshImageView startAnimating];
[UIView animateWithDuration:0.3 animations:^{
self.scrollView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0);
}];
} else if (refreshState == MHRefreshStateNormal) {
if (_refreshImageView.isAnimating) {
[_refreshImageView stopAnimating];
self.scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
}
}else if (refreshState == MHRefreshStateEndRresh){
if (_refreshImageView.isAnimating) {
[_refreshImageView stopAnimating];
[UIView animateWithDuration:0.3 animations:^{
self.scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
}];
}
}
}
//改變透明度
-(void)setPullingPercent:(CGFloat)percent
{
_refreshImageView.alpha = percent;
}
//滑動處理
- (void)updateRefreshHeaderWithOffsetY:(CGFloat)y
{
if (y > 0) {//防止往上劃的時候動圖顯示出來
return;
}
[self setPullingPercent:(fabs(y) - 20) / (fabs(RefreshMinY) - 20)];
if (self.refreshState == MHRefreshStateRefreshing) {
return;
}
if (y < RefreshMinY) {
if(!self.scrollView.isDragging ){
self.refreshState = MHRefreshStateRefreshing;
}
}else{
if (self.refreshState == MHRefreshStateNormal) {
return;
}
self.refreshState = MHRefreshStateNormal;
}
}
//監(jiān)聽滑動
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
if (keyPath != BaseRefreshViewObserveKeyPath) return;
[self updateRefreshHeaderWithOffsetY:self.scrollView.contentOffset.y];
}
@end
是不是很簡單呀?
然后再看看使用
_refreshHeader = [MHRefreshHeader refreshWithScroll:_tableView];
__weak typeof(self) weakSelf = self;
[_refreshHeader setRefreshingBlock:^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[weakSelf.refreshHeader endRefreshing];
});
}];
只有2步,通過scrollview創(chuàng)建,然后在刷新方法里面結(jié)束刷新.給大家提供個思路,有更好的辦法歡迎留言交流??
github地址