MJRefreshLefter
参照MJRefreshHeader改写支持ScrollView横向滚动刷新
MJRefreshLefter.h
#import "MJRefreshComponent.h"
@interface MJRefreshLefter : MJRefreshComponent
/** 创建header */
+ (instancetype)lefterWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)refreshingBlock;
/** 创建header */
+ (instancetype)lefterWithRefreshingTarget:(id)target refreshingAction:(SEL)action;
/** 这个key用来存储上一次下拉刷新成功的时间 */
@property (copy, nonatomic) NSString *lastUpdatedTimeKey;
/** 上一次下拉刷新成功的时间 */
@property (strong, nonatomic, readonly) NSDate *lastUpdatedTime;
/** 忽略多少scrollView的contentInset的top */
@property (assign, nonatomic) CGFloat ignoredScrollViewContentInsetLeft;
@end
MJRefreshComponent.m
#import "MJRefreshLefter.h"
@interface MJRefreshLefter()
@property (assign, nonatomic) CGFloat insetTDelta;
@property (nonatomic,strong) NSMutableDictionary * stateTextDictM;
@property (nonatomic,strong) UILabel * stateLbl;
@property (nonatomic,strong) UIImageView * arrowImageView;
@property (nonatomic,strong) UIActivityIndicatorView * indicator;
@end
@implementation MJRefreshLefter
+ (instancetype)lefterWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)refreshingBlock
{
MJRefreshLefter *cmp = [[MJRefreshLefter alloc] init];
cmp.refreshingBlock = refreshingBlock;
return cmp;
}
+ (instancetype)lefterWithRefreshingTarget:(id)target refreshingAction:(SEL)action
{
MJRefreshLefter *cmp = [[MJRefreshLefter alloc] init];
[cmp setRefreshingTarget:target refreshingAction:action];
return cmp;
}
#pragma mark - 覆盖父类的方法
- (void)prepare
{
[super prepare];
// 设置key
self.lastUpdatedTimeKey = @"MJRefreshLefterLastUpdatedTimeKey";
}
- (void)placeSubviews
{
[super placeSubviews];
// 设置y值(当自己的高度发生改变了,肯定要重新调整Y值,所以放到placeSubviews方法中设置y值)
self.mj_x = - self.mj_w - self.ignoredScrollViewContentInsetLeft;
}
- (void)willMoveToSuperview:(UIView *)newSuperview
{
[super willMoveToSuperview:newSuperview];
// 设置高度
self.mj_w = 54.0f;
self.mj_x = - self.mj_w - self.ignoredScrollViewContentInsetLeft;
self.scrollView.alwaysBounceVertical = NO;
self.scrollView.alwaysBounceHorizontal = YES;
[self addSubview:self.arrowImageView];
[self addSubview:self.stateLbl];
[self addSubview:self.indicator];
[self scrollViewPanStateDidChange:nil];
}
- (void)scrollViewContentOffsetDidChange:(NSDictionary *)change
{
[super scrollViewContentOffsetDidChange:change];
// 在刷新的refreshing状态
if (self.state == MJRefreshStateRefreshing) {
// 没有superView,也就是没加载到其他的View上
if (self.window == nil) return;
// ??????
// sectionheader停留解决
// CGFloat insetL = - self.scrollView.mj_offsetX > _scrollViewOriginalInset.left? _scrollView.mj_offsetX:_scrollViewOriginalInset.left;
// insetL = insetL > self.mj_w+_scrollViewOriginalInset.left?self.mj_h+_scrollViewOriginalInset.left:insetL;
// self.scrollView.mj_insetL = insetL;
//
// self.insetTDelta = _scrollViewOriginalInset.left-insetL;
return;
}
// 跳转到下一个控制器时,contentInset可能会变
_scrollViewOriginalInset = self.scrollView.contentInset;
// 当前的contentOffset
CGFloat offsetX = self.scrollView.mj_offsetX;
// 头部控件刚好出现的offsetY
CGFloat happenOffsetX = - self.scrollViewOriginalInset.left;
// 如果是向上滚动到看不见头部控件,直接返回
// >= -> >
if (offsetX > happenOffsetX) return;
// 普通 和 即将刷新 的临界点 忘下拉,offsetX是负数,往右拉offsetX是负数
CGFloat normal2pullingOffsetX = happenOffsetX - self.mj_w;
CGFloat pullingPercent = (happenOffsetX - offsetX) / self.mj_w;
if (self.scrollView.isDragging) {
self.pullingPercent = pullingPercent;
if (self.state == MJRefreshStateIdle && offsetX < normal2pullingOffsetX) {
// 转为即将刷新状态
self.state = MJRefreshStatePulling;
} else if (self.state == MJRefreshStatePulling && offsetX >= normal2pullingOffsetX) {
// 转为普通状态
self.state = MJRefreshStateIdle;
}
}else if (self.state == MJRefreshStatePulling) {// 即将刷新 && 手松开
// 开始刷新
[self beginRefreshing];
} else if (pullingPercent < 1) {
self.pullingPercent = pullingPercent;
}
}
- (void)scrollViewContentSizeDidChange:(NSDictionary *)change
{
[super scrollViewContentSizeDidChange:change];
self.mj_h = self.scrollView.mj_h;
self.arrowImageView.mj_y = (self.mj_h-self.arrowImageView.image.size.height)/2.0;
self.arrowImageView.mj_x = 15;
self.indicator.frame = self.arrowImageView.frame;
self.stateLbl.mj_x = self.arrowImageView.mj_w+15;
self.stateLbl.mj_h = self.mj_h;
self.mj_w = CGRectGetMidX(self.stateLbl.frame)+10;
self.mj_x = - self.mj_w - self.ignoredScrollViewContentInsetLeft;
NSLog(@"");
}
- (void)setState:(MJRefreshState)state
{
MJRefreshCheckState
self.stateLbl.text = self.stateTextDictM[@(state)];
// 根据状态做事情
if (state == MJRefreshStateIdle) {
self.arrowImageView.hidden = NO;
self.indicator.hidden = YES;
[self.indicator stopAnimating];
if (oldState == MJRefreshStatePulling) {
[UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
self.arrowImageView.transform = CGAffineTransformIdentity;
}];
}else{
self.arrowImageView.transform = CGAffineTransformIdentity;
}
if (oldState != MJRefreshStateRefreshing) return;
// 保存刷新时间
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:self.lastUpdatedTimeKey];
[[NSUserDefaults standardUserDefaults] synchronize];
// 恢复inset和offset
[UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{
self.scrollView.mj_insetL += self.insetTDelta;
// 自动调整透明度
if (self.isAutomaticallyChangeAlpha) self.alpha = 0.0;
} completion:^(BOOL finished) {
self.pullingPercent = 0.0;
self.scrollView.mj_insetL -= self.mj_w;
if (self.endRefreshingCompletionBlock) {
self.endRefreshingCompletionBlock();
}
}];
} else if (state == MJRefreshStateRefreshing) {
dispatch_async(dispatch_get_main_queue(), ^{
self.arrowImageView.hidden = YES;
self.indicator.hidden = NO;
[self.indicator startAnimating];
[UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
CGFloat left = self.scrollViewOriginalInset.left + self.mj_w;
// 增加滚动区域top
self.scrollView.mj_insetL = left;
// 设置滚动位置
//self.scrollView.mj_offsetX = -left;
[self.scrollView setContentOffset:CGPointMake(-left, 0) animated:NO];
} completion:^(BOOL finished) {
[self executeRefreshingCallback];
}];
});
}else if(state == MJRefreshStatePulling){
self.arrowImageView.hidden = NO;
self.indicator.hidden = YES;
[self.indicator stopAnimating];
[UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
self.arrowImageView.transform = CGAffineTransformMakeRotation(0.000001 - M_PI);
}];
}
}
#pragma mark - 公共方法
- (void)endRefreshing
{
dispatch_async(dispatch_get_main_queue(), ^{
self.state = MJRefreshStateIdle;
});
}
- (NSDate *)lastUpdatedTime
{
return [[NSUserDefaults standardUserDefaults] objectForKey:self.lastUpdatedTimeKey];
}
- (NSMutableDictionary *)stateTextDictM
{
if (_stateTextDictM == nil) {
_stateTextDictM = [NSMutableDictionary dictionary];
_stateTextDictM[@(MJRefreshStateIdle)] = @"右滑刷新数据";
_stateTextDictM[@(MJRefreshStatePulling)] = @"释放刷新";
_stateTextDictM[@(MJRefreshStateRefreshing)] = @"正在刷新";
}
return _stateTextDictM;
}
- (UILabel *)stateLbl
{
if (_stateLbl == nil) {
_stateLbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 20, 0)];
_stateLbl.text = self.stateTextDictM[@(self.state)];
_stateLbl.textColor = [UIColor blackColor];
_stateLbl.font = [UIFont systemFontOfSize:10];
_stateLbl.numberOfLines = 0;
_stateLbl.textAlignment = NSTextAlignmentCenter;
}
return _stateLbl;
}
- (UIImageView *)arrowImageView
{
if (_arrowImageView == nil) {
_arrowImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"右滑"]];
}
return _arrowImageView;
}
- (UIActivityIndicatorView *)indicator
{
if (_indicator == nil) {
_indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
_indicator.frame = self.arrowImageView.frame;
_indicator.hidden = YES;
}
return _indicator;
}
@end