首页 > 代码库 > 上拉加载下拉刷新控件WaterRefreshLoadMoreView
上拉加载下拉刷新控件WaterRefreshLoadMoreView
上拉加载下拉刷新控件WaterRefreshLoadMoreView
效果:
源码:
//// SRSlimeView// @author SR// Modified by JunHan on 13-9-18.//#import <UIKit/UIKit.h>#define kStartTo 0.7f#define kEndTo 0.15f#define kAnimationInterval (1.0f / 50.0f)NS_INLINE CGFloat distansBetween(CGPoint p1 , CGPoint p2) { return sqrtf((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));}typedef enum { SRSlimeStateNormal, SRSlimeStateShortening, SRSlimeStateMiss} SRSlimeState;@class SRSlimeView;@interface SRSlimeView : UIView@property (nonatomic, assign) CGPoint startPoint, toPoint;@property (nonatomic, assign) CGFloat viscous; //default 55@property (nonatomic, assign) CGFloat radius; //default 13@property (nonatomic, assign) CGFloat lineWith;@property (nonatomic, assign) CGFloat shadowBlur;@property (nonatomic, strong) UIColor *bodyColor, *skinColor;@property (nonatomic, strong) UIColor *shadowColor;@property (nonatomic, assign) SRSlimeState state;- (void)setPullApartTarget:(id)target action:(SEL)action;@end
//// SRSlimeView// @author SR// Modified by JunHan on 13-9-18.//#import "SRSlimeView.h"#import <QuartzCore/QuartzCore.h>NS_INLINE CGPoint pointLineToArc(CGPoint center, CGPoint p2, float angle, CGFloat radius) { float angleS = atan2f(p2.y - center.y, p2.x - center.x); float angleT = angleS + angle; float x = radius * cosf(angleT); float y = radius * sinf(angleT); return CGPointMake(x + center.x, y + center.y);}@implementation SRSlimeView { __weak id _target; SEL _action;}- (id)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { self.backgroundColor = [UIColor clearColor]; _toPoint = _startPoint = CGPointMake(frame.size.width / 2, frame.size.height / 2); _viscous = 45.0f; // 拉扯长度 _radius = 17.0f; // 拉扯物体半径 _bodyColor = [[UIColor grayColor] colorWithAlphaComponent:0.45f]; _skinColor = [[UIColor blackColor] colorWithAlphaComponent:0.12f]; _lineWith = 1.0; _shadowBlur = 4; _shadowColor = [[UIColor grayColor] colorWithAlphaComponent:0.7f]; } return self;}- (void)setLineWith:(CGFloat)lineWith{ _lineWith = lineWith; [self setNeedsDisplay];}- (void)setStartPoint:(CGPoint)startPoint{ if (CGPointEqualToPoint(_startPoint, startPoint)) return; if (_state == SRSlimeStateNormal) { _startPoint = startPoint; [self setNeedsDisplay]; }}- (void)setToPoint:(CGPoint)toPoint{ if (CGPointEqualToPoint(_toPoint, toPoint)) return; if (_state == SRSlimeStateNormal) { _toPoint = toPoint; [self setNeedsDisplay]; }}- (UIBezierPath*)bodyPath:(CGFloat)startRadius end:(CGFloat)endRadius percent:(float)percent{ UIBezierPath *path = [[UIBezierPath alloc] init]; float angle1 = M_PI/3 + (M_PI/6) * percent; CGPoint sp1 = pointLineToArc(_startPoint, _toPoint, angle1, startRadius), sp2 = pointLineToArc(_startPoint, _toPoint, -angle1, startRadius), ep1 = pointLineToArc(_toPoint, _startPoint, M_PI/2, endRadius), ep2 = pointLineToArc(_toPoint, _startPoint, -M_PI/2, endRadius);#define kMiddleP 0.6 CGPoint mp1 = CGPointMake(sp2.x*kMiddleP + ep1.x*(1-kMiddleP), sp2.y*kMiddleP + ep1.y*(1-kMiddleP)), mp2 = CGPointMake(sp1.x*kMiddleP + ep2.x*(1-kMiddleP), sp1.y*kMiddleP + ep2.y*(1-kMiddleP)), mm = CGPointMake((mp1.x + mp2.x)/2, (mp1.y + mp2.y)/2); float p = distansBetween(mp1, mp2) / 2 / endRadius * (0.9 + percent/10); mp1 = CGPointMake((mp1.x - mm.x)/p + mm.x, (mp1.y - mm.y)/p + mm.y); mp2 = CGPointMake((mp2.x - mm.x)/p + mm.x, (mp2.y - mm.y)/p + mm.y); [path moveToPoint:sp1]; float angleS = atan2f(_toPoint.y - _startPoint.y, _toPoint.x - _startPoint.x); [path addArcWithCenter:_startPoint radius:startRadius startAngle:angleS + angle1 endAngle:angleS + M_PI*2 - angle1 clockwise:YES]; [path addQuadCurveToPoint:ep1 controlPoint:mp1]; angleS = atan2f(_startPoint.y - _toPoint.y, _startPoint.x - _toPoint.x); [path addArcWithCenter:_toPoint radius:endRadius startAngle:angleS + M_PI/2 endAngle:angleS + M_PI*3/2 clockwise:YES]; [path addQuadCurveToPoint:sp1 controlPoint:mp2]; return path;}- (void)drawRect:(CGRect)rect{ switch (_state) { case SRSlimeStateNormal: { float percent = 1 - distansBetween(_startPoint , _toPoint) / _viscous; if (percent == 1) { CGContextRef context = UIGraphicsGetCurrentContext(); UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(_startPoint.x - _radius, _startPoint.y - _radius, 2*_radius, 2*_radius) cornerRadius:_radius]; [self setContext:context path:path]; CGContextDrawPath(context, kCGPathFillStroke); }else { CGFloat startRadius = _radius * (kStartTo + (1 - kStartTo) * percent); CGFloat endRadius = _radius * (kEndTo + (1 - kEndTo) * percent); CGContextRef context = UIGraphicsGetCurrentContext(); // build curve path UIBezierPath *path = [self bodyPath:startRadius end:endRadius percent:percent]; [self setContext:context path:path]; CGContextDrawPath(context, kCGPathFillStroke); if (percent <= 0) { _state = SRSlimeStateShortening;#pragma clang diagnostic push#pragma clang diagnostic ignored "-Warc-performSelector-leaks" [_target performSelector:_action withObject:self];#pragma clang diagnostic pop [self performSelector:@selector(scaling) withObject:nil afterDelay:kAnimationInterval inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; } } } break; case SRSlimeStateShortening: { // back shortneing _toPoint = CGPointMake((_toPoint.x - _startPoint.x) * 0.8 + _startPoint.x, (_toPoint.y - _startPoint.y) * 0.8 + _startPoint.y); float p = distansBetween(_startPoint, _toPoint) / _viscous; float percent = 1 - p; float r = _radius * p; if (p > 0.01) { CGFloat startRadius = r * (kStartTo + (1 - kStartTo) * percent); CGContextRef context = UIGraphicsGetCurrentContext(); CGFloat endRadius = r * (kEndTo + (1 - kEndTo) * percent) * (1 + percent / 2); UIBezierPath *path = [self bodyPath:startRadius end:endRadius percent:percent]; [self setContext:context path:path]; CGContextDrawPath(context, kCGPathFillStroke); }else { self.hidden = YES; _state = SRSlimeStateMiss; } } break; default: break; }}- (void)setContext:(CGContextRef)context path:(UIBezierPath *)path { if (self.shadowColor) { CGContextSetShadowWithColor(context, CGSizeZero, self.shadowBlur, self.shadowColor.CGColor); } CGContextSetFillColorWithColor(context, self.bodyColor.CGColor); CGContextSetLineWidth(context, self.lineWith); CGContextSetStrokeColorWithColor(context, self.skinColor.CGColor); CGContextAddPath(context, path.CGPath);}- (void)scaling{ if (_state == SRSlimeStateShortening) { [self setNeedsDisplay]; [self performSelector:@selector(scaling) withObject:nil afterDelay:kAnimationInterval inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; }}- (void)setPullApartTarget:(id)target action:(SEL)action{ _target = target; _action = action;}- (void)setHidden:(BOOL)hidden{ [super setHidden:hidden]; if (!hidden) { self.layer.transform = CATransform3DIdentity; [self setNeedsDisplay]; }}- (void)setState:(SRSlimeState)state{ _state = state; [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(scaling) object:nil];}@end
/** * WaterRefreshLoadMoreView.h * A refresh view looks like UIRefreshControl and have loadMore function * (水滴下拉刷新,上拉加载) * * 使用方法:(可设置type类型,默认是下拉上拉都有) * 1. 直接initWithType创建,然后将它的scrollView赋值,别忘了在使用它的ScrollView 或者 VC的dealloc * 中调用这个 deallocWithCloseConnect 方法 * * Created by 覃俊涵 on 13-9-18. All rights reserved. **/#import <UIKit/UIKit.h>#import "SRSlimeView.h"typedef enum{ WaterRefreshTypeRefreshAndLoadMore,//含下拉上拉(default) WaterRefreshTypeOnlyRefresh, //仅下拉刷新 WaterRefreshTypeOnlyLoadMore, //仅加载更多 WaterRefreshTypeNone}WaterViewType;@protocol WaterRefreshDelegate;@protocol WaterLoadMoreDelegate;@interface WaterRefreshLoadMoreView : UIView@property (nonatomic, weak) UIScrollView *scrollView;@property (nonatomic, assign) WaterViewType type;// 水下拉的view@property (nonatomic, weak) UIView *waterRefreshView;// 上拉的view@property (nonatomic, strong) UIView *loadMoreView;// 水滴中央的图片样式@property (nonatomic, strong) UIImageView *refleshView;// 刷新提示字时 前方显示的 图片样式@property (nonatomic, strong) UIImageView *refreshRemindPicView;// refresh上的提示label@property (nonatomic, strong) UILabel *refreshRemind;// loadMore上的提示label@property (nonatomic, strong) UILabel *loadMoreRemind;// loadMore转圈时显示的文字,比如 "加载中..",没有设置则转动图样居中显示@property (nonatomic, strong) NSString *loadMoreIndicatorWord;@property (nonatomic, weak) id <WaterRefreshDelegate> refreshDelegate;@property (nonatomic, weak) id <WaterLoadMoreDelegate> loadMoreDelegate;@property (nonatomic, assign, readonly) BOOL isRefreshing;@property (nonatomic, assign, readonly) BOOL isLoadingMore;// initial method- (id)initWithWithType:(WaterViewType)type;// !你需要在使用它的ScrollView 或者 VC的dealloc中调用这个方法- (void)deallocWithCloseConnect;/*w start: 自动开始水滴下拉刷新自动开始,另一种是靠你手去拖动触发 end : 结束水滴下拉刷新并显示提示动画,请传入提示语,你可能会想提示:"刷新成功", 可指定提示图片 */- (void)startRefreshWithExpansion;- (void)startRefreshWithExpansionWithoutDelegate;- (void)endRefreshWithRemindsWords:(NSString *)remind remindImage:(UIImage *)remindImage;/* start: 自动开始上拉加载,另一种是靠手去上拉 end : 停止上拉加载,可给予提示 */- (void)startLoadingMoreExpansion;- (void)startLoadingMoreExpansionWithOutDelegate;- (void)endLoadingMoreWithRemind:(NSString *)remind;// 禁掉loadMore的上拉加载功能,ban为YES时提示语默认为“没有更多内容”- (void)banFunctionOfStartLoadMore:(BOOL)ban remind:(NSString *)remind;- (void)setWaterRefreshColor:(UIColor*)color;@end@protocol WaterRefreshDelegate <NSObject>// 水滴下拉刷新的代理方法- (void)slimeRefreshStartRefresh:(WaterRefreshLoadMoreView*)refreshView;- (void)slimeRefreshEndRefresh:(WaterRefreshLoadMoreView *)refreshView;@end@protocol WaterLoadMoreDelegate <NSObject>@optional// 加载更多的代理方法- (void)loadMoreViewStartLoad:(WaterRefreshLoadMoreView*)refreshView;- (void)loadMoreViewEndLoad:(WaterRefreshLoadMoreView *)refreshView;@end
//// WaterRefreshLoadMoreView.m// shiyanforwaterfresh//// Created by 俊涵 on 13-9-19.// Copyright (c) 2013年 俊涵. All rights reserved.//#import "WaterRefreshLoadMoreView.h"#import "SRSlimeView.h"#import <QuartzCore/QuartzCore.h>#define KEYPATH_CONTENTOFFSET @"contentOffset"#define KEYPATH_CONTENTSIZE @"contentSize"#define STRING_LOADMORE @"加载更多"#define STRING_NOMORE @"没有更多内容"#define HEIGHT_DEFAULT 40.0f#define DURIATION_ANIMATE 0.2f#define DURIATION_SHOWNOMORE 1.5f#define TAG_LOADMORE_INDICATOR 200#define kRefreshImageWidth 20.0f#define kDistanceFromRemind 10.0fstatic int scrollViewObservanceContext;static int scrollViewContentSizeContext;typedef enum { FooterViewStateNormal, FooterViewStateNormalPullling, FooterViewStateLoadingMore}FooterViewState;@interface WaterRefreshLoadMoreView(){ UIImageView *_refleshView; SRSlimeView *_slime;}@property (nonatomic, assign) FooterViewState footerState;@property (nonatomic, strong) SRSlimeView *slime;@property (nonatomic, strong) UIActivityIndicatorView *loadMoreActivityView;@property (nonatomic, assign) BOOL closeLoadMore;@property (nonatomic, assign) BOOL endAnimation;@property (nonatomic, assign) BOOL endRefreshWithRemind;@property (nonatomic, assign) BOOL broken;@property (nonatomic, assign) BOOL slimeMissWhenGoingBack;@property (nonatomic, assign) BOOL lastDragScroll;@property (nonatomic, assign) BOOL isHasMoreContent;@property (nonatomic, assign) CGFloat upInset;@property (nonatomic, strong) NSString *refreshRemindWord;@property (nonatomic, strong) NSString *loadMoreRemindWord;@property (nonatomic, strong) UITapGestureRecognizer *gesture;@end@implementation WaterRefreshLoadMoreView { UIActivityIndicatorView *_activityIndicatorView; CGFloat _oldLength; BOOL _unmissSlime; CGFloat _dragingHeight;}- (id)initWithFrame:(CGRect)frame{ self = [self initWithHeight:HEIGHT_DEFAULT]; return self;}- (id)initWithWithType:(WaterViewType)type{ self = [self initWithHeight:HEIGHT_DEFAULT]; self.type = type; return self;}- (id)initWithHeight:(CGFloat)height{ CGRect frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, height); self = [super initWithFrame:frame]; if (self) { // slime _slime = [[SRSlimeView alloc] initWithFrame:self.bounds]; _slime.startPoint = CGPointMake(frame.size.width / 2, height / 2); [self addSubview:_slime]; [_slime setPullApartTarget:self action:@selector(pullApart:)]; // 刷新图样 _refleshView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"waterRefreshLoadMore_refresh"]]; _refleshView.center = _slime.startPoint; _refleshView.bounds = CGRectMake(0.0f, 0.0f, kRefreshImageWidth, kRefreshImageWidth); [self addSubview:_refleshView]; // indicator _activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleGray]; _activityIndicatorView.center = _slime.startPoint; [self addSubview:_activityIndicatorView]; // refreshRemind self.refreshRemind = [[UILabel alloc] initWithFrame:_slime.frame]; [self addSubview:self.refreshRemind]; self.refreshRemind.backgroundColor = [UIColor clearColor]; self.refreshRemind.textAlignment = NSTextAlignmentCenter; self.refreshRemind.textColor = [UIColor grayColor]; self.refreshRemind.font = [UIFont systemFontOfSize:13.0f]; self.refreshRemind.hidden = YES; // refreshRemindPicView self.refreshRemindPicView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, kRefreshImageWidth, kRefreshImageWidth)]; [self addSubview:self.refreshRemindPicView]; self.refreshRemindPicView.hidden = YES; // 设置拖拽临界点的高度 _dragingHeight = height; self.slimeMissWhenGoingBack = NO; self.waterRefreshView = self; } return self;}- (void)setWaterRefreshColor:(UIColor*)color{ [_activityIndicatorView setColor:color]; self.refreshRemind.textColor = color; // _slime.bodyColor = color;}- (void)didMoveToSuperview{ [super didMoveToSuperview]; if ([self.superview isKindOfClass:[UIScrollView class]]) { _scrollView = (id)[self superview]; if (self.type == WaterRefreshTypeRefreshAndLoadMore || self.type == WaterRefreshTypeOnlyLoadMore) { [self addLoadMoreView]; } self.isHasMoreContent = YES; // config frame CGRect rect = self.frame; rect.origin.y = rect.size.height ? -rect.size.height : -_dragingHeight; rect.size.width = _scrollView.frame.size.width; self.frame = rect; // inset UIEdgeInsets inset = self.scrollView.contentInset; inset.top = _upInset; self.scrollView.contentInset = inset; [self.scrollView addObserver:self forKeyPath:KEYPATH_CONTENTOFFSET options:0 context:&scrollViewObservanceContext]; [self.scrollView addObserver:self forKeyPath:KEYPATH_CONTENTSIZE options:0 context:&scrollViewContentSizeContext]; // configLoadMoreHide [self configLoadMoreHide]; }else if (!self.superview) { self.scrollView = nil; }}- (void)addLoadMoreView{ // add loadmore CGFloat maxTop = self.scrollView.frame.size.height > self.scrollView.contentSize.height ? self.scrollView.frame.size.height : self.scrollView.contentSize.height; self.loadMoreView = [[UIView alloc] initWithFrame:CGRectMake(0, maxTop, [UIScreen mainScreen].bounds.size.width, HEIGHT_DEFAULT)]; [self.scrollView addSubview:self.loadMoreView]; self.loadMoreView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; self.loadMoreActivityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; self.loadMoreActivityView.tag = TAG_LOADMORE_INDICATOR; [self.loadMoreView addSubview:self.loadMoreActivityView]; self.loadMoreActivityView.center = CGPointMake(self.loadMoreView.frame.size.width / 2, self.loadMoreView.frame.size.height / 2); [self showLoadMoreRemind:STRING_LOADMORE]; // config loadMoreRemind self.loadMoreRemind = [[UILabel alloc] initWithFrame:self.loadMoreView.bounds]; self.loadMoreRemind.backgroundColor = [UIColor clearColor]; self.loadMoreRemind.font = [UIFont systemFontOfSize:12.0f]; self.loadMoreRemind.textColor = [UIColor grayColor]; self.loadMoreRemind.textAlignment = NSTextAlignmentCenter; [self.loadMoreView addSubview:self.loadMoreRemind]; //self.loadMoreRemind.hidden = NO; [self showLoadMoreRemind:STRING_LOADMORE]; // gesture self.gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(loadMoreActionByClick)]; [self.loadMoreView addGestureRecognizer:self.gesture]; self.footerState = FooterViewStateNormal; [self configLoadMoreHide];}- (void)loadMoreActionByClick{ [self scrollViewDataSourceDidStartLoadingMore:self.scrollView];}- (void)dealloc{ [self clearObservance];}- (void)deallocWithCloseConnect // TODO :换成更好的办法{ [self clearObservance];}- (void)clearObservance{ [self.scrollView removeObserver:self forKeyPath:KEYPATH_CONTENTOFFSET context:&scrollViewObservanceContext]; [self.scrollView removeObserver:self forKeyPath:KEYPATH_CONTENTSIZE context:&scrollViewContentSizeContext]; self.scrollView = nil;}- (void)removeFromSuperview{ [NSObject cancelPreviousPerformRequestsWithTarget:self]; [super removeFromSuperview];}#pragma mark - setters And getter- (void)setScrollView:(UIScrollView *)scrollView{ if (_scrollView != scrollView) { _scrollView = scrollView; if (self.superview) { [self.loadMoreView removeFromSuperview]; self.loadMoreView = nil; [self removeFromSuperview]; } [self.scrollView addSubview:self]; }}- (void)setType:(WaterViewType)type{ if (self.type == type) { return; } if (self.type != WaterRefreshTypeNone) { [self.scrollView removeObserver:self forKeyPath:KEYPATH_CONTENTOFFSET context:&scrollViewObservanceContext]; [self.scrollView removeObserver:self forKeyPath:KEYPATH_CONTENTSIZE context:&scrollViewContentSizeContext]; } _type = type; _isLoadingMore = NO; [self setFooterState:FooterViewStateNormal]; self.closeLoadMore = NO; // 如果切换类型之前动画还未结束 if (self.endAnimation == NO) { self.endAnimation = YES; } self.endRefreshWithRemind = NO; [self endRefreshWithRemindsWords:@"" remindImage:nil]; [self endLoadingMoreWithRemind:@""]; [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(collapse) object:nil]; [self backStateOfScrollView]; if (type == WaterRefreshTypeRefreshAndLoadMore || type == WaterRefreshTypeOnlyRefresh) { self.hidden = NO; self.loadMoreView.hidden = NO; UIScrollView *scrollView = self.scrollView; self.scrollView = nil; //clear self.scrollView = scrollView; } else if (type == WaterRefreshTypeOnlyLoadMore) { self.loadMoreView.hidden = NO; self.hidden = YES; UIScrollView *scrollView = self.scrollView; self.scrollView = nil; //clear self.scrollView = scrollView; } else if(type == WaterRefreshTypeNone) { self.hidden = YES; self.loadMoreView.hidden = YES; }}- (void)backStateOfScrollView{ UIEdgeInsets inset = self.scrollView.contentInset; inset.top = _upInset; inset.bottom = 0.0f; self.scrollView.contentInset = inset;}- (void)setFrame:(CGRect)frame{ [super setFrame:frame]; if (_slime.state == SRSlimeStateNormal) { _slime.frame = CGRectMake(0.0f, 0.0f, frame.size.width, frame.size.height); _slime.startPoint = CGPointMake(frame.size.width / 2, _dragingHeight / 2); } _refleshView.center = _slime.startPoint; _activityIndicatorView.center = _slime.startPoint;}- (void)setUpInset:(CGFloat)upInset{ _upInset = upInset; UIEdgeInsets inset = _scrollView.contentInset; inset.top = _upInset; _scrollView.contentInset = inset;}- (void)setSlimeMissWhenGoingBack:(BOOL)slimeMissWhenGoingBack{ _slimeMissWhenGoingBack = slimeMissWhenGoingBack; if (!slimeMissWhenGoingBack) { _slime.alpha = 1; }else { CGPoint p = _scrollView.contentOffset; self.alpha = -(p.y + _upInset) / _dragingHeight; }}#pragma mark - Scroll handle- (void)scrollViewDidScroll{ CGPoint offset = _scrollView.contentOffset; CGRect rect = self.frame; // 下拉刷新 if (self.type == WaterRefreshTypeRefreshAndLoadMore || self.type == WaterRefreshTypeOnlyRefresh) { if (offset.y <= - _dragingHeight - _upInset) { // 处于拉伸变形的状态 rect.origin.y = offset.y + _upInset; rect.size.height = -offset.y; rect.size.height = ceilf(rect.size.height); self.frame = rect; //special setFrame if (!self.isRefreshing) { [_slime setNeedsDisplay]; } if (!_broken) { float l = -(offset.y + _dragingHeight + _upInset); if (l <= _oldLength) { // 往回的时候 l = MIN(distansBetween(_slime.startPoint, _slime.toPoint), l); CGPoint ssp = _slime.startPoint; _slime.toPoint = CGPointMake(ssp.x, ssp.y + l); CGFloat pf = (1.0f - l / _slime.viscous) * (1.0f - kStartTo) + kStartTo; _refleshView.layer.transform = CATransform3DMakeScale(pf, pf, 1); }else if (self.scrollView.isDragging) { // 手拽着往下拉伸的时候 CGPoint ssp = _slime.startPoint; _slime.toPoint = CGPointMake(ssp.x, ssp.y + l); CGFloat pf = (1.0f - l / _slime.viscous) * (1.0f - kStartTo) + kStartTo; _refleshView.layer.transform = CATransform3DMakeScale(pf, pf, 1); } _oldLength = l; } if (self.alpha != 1.0f) self.alpha = 1.0f; //拉出来显示的时候可能 alpha不为1 }else if (offset.y < -_upInset) { rect.origin.y = -_dragingHeight; rect.size.height = _dragingHeight; self.frame = rect; [_slime setNeedsDisplay]; _slime.toPoint = _slime.startPoint; if (_slimeMissWhenGoingBack) self.alpha = -(offset.y + _upInset) / _dragingHeight; } if (self.isRefreshing && self.broken == NO) { // 配合适应inset避免 使用 tableview的话 section位置浮动错误 UIEdgeInsets inset = _scrollView.contentInset; CGFloat offsetmath = MAX(_scrollView.contentOffset.y * -1, 0); offsetmath = MIN(offsetmath, HEIGHT_DEFAULT); inset.top = offsetmath; _scrollView.contentInset = inset; } } if ((self.type == WaterRefreshTypeRefreshAndLoadMore || self.type == WaterRefreshTypeOnlyLoadMore) && self.closeLoadMore == NO) { // 上拉 if (self.footerState == FooterViewStateNormal) { if (self.scrollView.isDragging && [self offsetFromBottom:self.scrollView] > self.loadMoreView.frame.size.height + 5) { [self setFooterState:FooterViewStateNormalPullling]; if (self.isHasMoreContent == NO) { } else { [self scrollViewDataSourceDidStartLoadingMore:self.scrollView]; } } } else if (self.footerState == FooterViewStateNormalPullling) { if (self.scrollView.isDragging && [self offsetFromBottom:self.scrollView] < self.frame.size.height + 5) { [self setFooterState:FooterViewStateNormal]; } } else if (self.footerState == FooterViewStateLoadingMore) { } }}- (void)scrollViewDidEndDraging{ // 下拉刷新 if (self.type == WaterRefreshTypeRefreshAndLoadMore || self.type == WaterRefreshTypeOnlyRefresh) { if (_broken) { self.broken = NO; if (self.isRefreshing) { [UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; [UIView animateWithDuration:DURIATION_ANIMATE animations:^{ UIEdgeInsets inset = _scrollView.contentInset; inset.top = _upInset + _dragingHeight; _scrollView.contentInset = inset; } completion:^(BOOL finished) { }]; } } } // 上拉 if ((self.type == WaterRefreshTypeRefreshAndLoadMore || self.type == WaterRefreshTypeOnlyLoadMore) && self.closeLoadMore == NO) { if (self.footerState == FooterViewStateNormalPullling) { if (self.isHasMoreContent == NO) { } else { [self scrollViewDataSourceDidStartLoadingMore:self.scrollView]; } } }}#pragma mark - loadMore- (void)relayoutLoadMoreViewAndInset{ if (self.closeLoadMore == YES) { return; } CGFloat max = self.scrollView.contentSize.height < self.scrollView.frame.size.height ? self.scrollView.frame.size.height - self.scrollView.contentSize.height : 0; UIEdgeInsets inset = self.scrollView.contentInset; inset.bottom = max + self.loadMoreView.frame.size.height; self.scrollView.contentInset = inset; CGFloat footerViewTop = MAX(self.scrollView.frame.size.height, self.scrollView.contentSize.height); self.loadMoreView.frame = CGRectMake(0, footerViewTop, self.loadMoreView.frame.size.width, self.loadMoreView.frame.size.height);}- (void)configLoadMoreHide{ if (self.type == WaterRefreshTypeRefreshAndLoadMore || self.type == WaterRefreshTypeOnlyLoadMore) { if (self.scrollView.contentSize.height < self.scrollView.frame.size.height) { self.loadMoreView.hidden = YES; self.closeLoadMore = YES; UIEdgeInsets inset = self.scrollView.contentInset; inset.bottom = 0.0f; self.scrollView.contentInset = inset; } else { self.loadMoreView.hidden = YES; self.closeLoadMore = YES; UIEdgeInsets inset = self.scrollView.contentInset; inset.bottom = self.loadMoreView.frame.size.height; self.scrollView.contentInset = inset; self.loadMoreView.hidden = NO; self.closeLoadMore = NO; } }}- (void)startLoadingMoreExpansion{ [self scrollViewDataSourceDidStartLoadingMore:self.scrollView];}- (void)startLoadingMoreExpansionWithOutDelegate{ [self scrollViewDataSourceDidStartLoadingMoreWithOutDelegate:self.scrollView];}- (void)endLoadingMoreWithRemind:(NSString *)remind{ if (self.type == WaterRefreshTypeNone || self.type == WaterRefreshTypeOnlyRefresh) { return; } if (_isLoadingMore) { self.loadMoreRemindWord = remind; [self safeStopLoadingMore:self.scrollView]; }}- (void)safeStartLoadingMore:(UIScrollView *)scrollView{ if (!_isLoadingMore) { _isLoadingMore = YES; } else { return; } [self endRefreshWithRemindsWords:nil remindImage:nil]; [self setFooterState:FooterViewStateLoadingMore]; self.gesture.enabled = NO; self.loadMoreView.hidden = NO; [self showLoadMoreRemind:@""]; //清空 [self.loadMoreActivityView startAnimating]; // config 转动时提示 [self configIndicatorPositionWithWord:self.loadMoreIndicatorWord]; self.loadMoreRemind.alpha = 0.45f; // cofig animate with indicatorword NSTimeInterval animateDuration = 0.7f; [UIView animateWithDuration:animateDuration animations:^{ self.loadMoreRemind.alpha = 1.0f; }]; CAKeyframeAnimation *aniamtion = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; aniamtion.values = [NSArray arrayWithObjects: [NSValue valueWithCATransform3D: CATransform3DRotate(CATransform3DMakeScale(0.01, 0.01, 0.1), -M_PI, 0, 0, 1)], [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.6, 1.6, 1)], [NSValue valueWithCATransform3D:CATransform3DIdentity], nil]; aniamtion.keyTimes = [NSArray arrayWithObjects: [NSNumber numberWithFloat:0], [NSNumber numberWithFloat:0.6], [NSNumber numberWithFloat:1], nil]; aniamtion.timingFunctions = [NSArray arrayWithObjects: [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseInEaseOut], [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseInEaseOut], nil]; aniamtion.duration = animateDuration; self.loadMoreActivityView.layer.transform = CATransform3DIdentity; [self.loadMoreActivityView.layer addAnimation:aniamtion forKey:@""]; }- (void)safeStopLoadingMore:(UIScrollView *)scrollView{ if (!_isLoadingMore) { return; } [UIView setAnimationCurve:UIViewAnimationCurveEaseIn]; [UIView animateWithDuration:0.2f animations:^{ self.loadMoreActivityView.layer.transform = CATransform3DRotate(CATransform3DMakeScale(0.01f, 0.01f, 0.1f), -M_PI, 0, 0, 1); self.loadMoreRemind.alpha = 0.2f; } completion:^(BOOL finished) { [self.loadMoreActivityView stopAnimating]; self.loadMoreActivityView.layer.transform = CATransform3DRotate(CATransform3DMakeScale(1.0f, 1.0f, 1.0f), M_PI, 0, 0, 1); self.loadMoreRemind.alpha = 1.0f; [self relayoutLoadMoreViewAndInset]; if (self.isHasMoreContent) { if (self.loadMoreRemindWord) { //错误提示语 [self showLoadMoreRemind:self.loadMoreRemindWord]; [self performSelector:@selector(backToLoadMoreRemind) withObject:nil afterDelay:1.0f]; } else { [self showLoadMoreRemind:STRING_LOADMORE]; _isLoadingMore = NO; [self setFooterState:FooterViewStateNormal]; self.gesture.enabled = YES; if ([self.loadMoreDelegate respondsToSelector:@selector(loadMoreViewEndLoad:)]) { [self.loadMoreDelegate loadMoreViewEndLoad:self]; } } } else { if (self.loadMoreRemindWord) { if ([self.loadMoreRemindWord isEqualToString:@""]) { self.loadMoreRemindWord = STRING_NOMORE; } [self showLoadMoreRemind:self.loadMoreRemindWord]; } else { [self showNoContentRemind]; } [self performSelector:@selector(setInsetBottomAnimateToZeroAndCallDelegate:) withObject:[NSNumber numberWithBool:YES] afterDelay:DURIATION_SHOWNOMORE]; } }];}- (void)setInsetBottomAnimateToZeroAndCallDelegate:(NSNumber *)callDelegate{ [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; [UIView animateWithDuration:DURIATION_ANIMATE animations:^{ [self setInsetBottomToZero]; } completion:^(BOOL finished) { _isLoadingMore = NO; [self setFooterState:FooterViewStateNormal]; if (self.isHasMoreContent) { self.gesture.enabled = YES; } if (callDelegate.boolValue) { if ([self.loadMoreDelegate respondsToSelector:@selector(loadMoreViewEndLoad:)]) { [self.loadMoreDelegate loadMoreViewEndLoad:self]; } }; }]; [UIView commitAnimations];}- (void)setInsetBottomToZero{ UIEdgeInsets currentInsets = self.scrollView.contentInset; currentInsets.bottom = 0; self.scrollView.contentInset = currentInsets;}- (void)scrollViewDataSourceDidStartLoadingMore:(UIScrollView *)scrollView{ if (!_isLoadingMore) { [self safeStartLoadingMore:scrollView]; if ([self.loadMoreDelegate respondsToSelector:@selector(loadMoreViewStartLoad:)]) { [self.loadMoreDelegate loadMoreViewStartLoad:self]; } }}- (void)scrollViewDataSourceDidStartLoadingMoreWithOutDelegate:(UIScrollView *)scrollView{ [self safeStartLoadingMore:scrollView];}- (void)scrollViewDataSourceDidFinishLoadingMore:(UIScrollView *)scrollView{ [self safeStopLoadingMore:scrollView];}- (CGFloat)offsetFromBottom:(UIScrollView *)scrollView{ CGFloat change = scrollView.contentSize.height < scrollView.frame.size.height ? 0 : scrollView.contentSize.height - scrollView.frame.size.height; return scrollView.contentOffset.y - change;}- (void)showNoContentRemind{ self.loadMoreRemind.hidden = NO; [self showLoadMoreRemind:STRING_NOMORE];}- (void)showLoadMoreRemind:(NSString *)remindword{ self.loadMoreActivityView.hidden = YES; self.loadMoreRemind.hidden = NO; self.loadMoreRemind.text = remindword; self.loadMoreRemind.center = CGPointMake(self.loadMoreView.frame.size.width / 2, self.loadMoreView.frame.size.height / 2); self.loadMoreRemindWord = nil; //clear}- (void)backToLoadMoreRemind{ UILabel *label = self.loadMoreRemind; [UIView animateWithDuration:0.3f animations:^{ label.alpha = 0.0f; } completion:^(BOOL finished) { [self showLoadMoreRemind:STRING_LOADMORE]; [UIView animateWithDuration:0.3f animations:^{ label.alpha = 1.0f; self.gesture.enabled = YES; _isLoadingMore = NO; [self setFooterState:FooterViewStateNormal]; if ([self.loadMoreDelegate respondsToSelector:@selector(loadMoreViewEndLoad:)]) { [self.loadMoreDelegate loadMoreViewEndLoad:self]; } }]; }];}- (void)banFunctionOfStartLoadMore:(BOOL)ban remind:(NSString *)remind{ if (ban) { self.gesture.enabled = NO; self.isHasMoreContent = NO; if (remind) { self.loadMoreRemind.text = remind; [self endLoadingMoreWithRemind:remind]; } else { self.loadMoreRemind.text = STRING_NOMORE; [self endLoadingMoreWithRemind:STRING_NOMORE]; } [self performSelector:@selector(setInsetBottomAnimateToZeroAndCallDelegate:) withObject:[NSNumber numberWithBool:NO] afterDelay:DURIATION_SHOWNOMORE]; } else { self.gesture.enabled = YES; self.isHasMoreContent = YES; if (!_isLoadingMore) { [self showLoadMoreRemind:STRING_LOADMORE]; } }}- (void)configIndicatorPositionWithWord:(NSString *)word{ if (word && ![word isEqualToString:@""]) { // 如果有提供的文字就做左偏移 self.loadMoreRemind.hidden = NO; self.loadMoreRemind.alpha = 1.0f; self.loadMoreRemind.text = word; CGSize size = [word sizeWithFont:self.loadMoreRemind.font constrainedToSize:CGSizeMake(self.loadMoreView.bounds.size.width, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping]; CGRect rect = self.loadMoreRemind.frame; rect.size.width = size.width; rect.size.height = size.height; self.loadMoreRemind.frame = rect; self.loadMoreRemind.center = CGPointMake(self.loadMoreView.frame.size.width / 2, self.loadMoreView.frame.size.height / 2); self.loadMoreActivityView.center = CGPointMake(self.loadMoreRemind.frame.origin.x - kDistanceFromRemind, self.loadMoreActivityView.center.y); [self alignmentWithView:self.loadMoreActivityView lable:self.loadMoreRemind distance:kDistanceFromRemind totalWidth:self.scrollView.frame.size.width]; } else { //还原 self.loadMoreRemind.hidden = YES; UIActivityIndicatorView *indicator = (UIActivityIndicatorView *)[self.loadMoreView viewWithTag:TAG_LOADMORE_INDICATOR]; indicator.center = CGPointMake(self.loadMoreView.frame.size.width / 2, self.loadMoreView.frame.size.height / 2); self.loadMoreRemind.center = indicator.center; }}- (void)alignmentWithView:(UIView *)view lable:(UILabel *)label distance:(CGFloat)distance totalWidth:(CGFloat)totalWidth{ CGFloat viewWidths = view.frame.size.width + distance + label.frame.size.width; CGFloat left = (totalWidth - viewWidths) / 2; view.center = CGPointMake(left + view.frame.size.width / 2 , view.center.y); label.center = CGPointMake(view.center.x + view.frame.size.width /2 + distance + label.frame.size.width / 2, label.center.y);}#pragma mark - refresh- (void)setIsRefreshing:(BOOL)isRefreshing{ if (_isRefreshing == isRefreshing) { return; } _isRefreshing = isRefreshing; if (_isRefreshing) { [self endLoadingMoreWithRemind:nil]; [_activityIndicatorView.layer removeAllAnimations]; [_activityIndicatorView startAnimating]; CAKeyframeAnimation *aniamtion = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; aniamtion.values = [NSArray arrayWithObjects: [NSValue valueWithCATransform3D: CATransform3DRotate(CATransform3DMakeScale(0.01, 0.01, 0.1), -M_PI, 0, 0, 1)], [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.6, 1.6, 1)], [NSValue valueWithCATransform3D:CATransform3DIdentity], nil]; aniamtion.keyTimes = [NSArray arrayWithObjects: [NSNumber numberWithFloat:0], [NSNumber numberWithFloat:0.6], [NSNumber numberWithFloat:1], nil]; aniamtion.timingFunctions = [NSArray arrayWithObjects: [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseInEaseOut], [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseInEaseOut], nil]; aniamtion.duration = 0.7; aniamtion.delegate = self; _activityIndicatorView.layer.transform = CATransform3DIdentity; [_activityIndicatorView.layer addAnimation:aniamtion forKey:@""]; _refleshView.hidden = YES; if (!_unmissSlime){ _slime.state = SRSlimeStateMiss; }else { _unmissSlime = NO; } }else { // 刷新结束 [_activityIndicatorView stopAnimating]; [_activityIndicatorView.layer removeAllAnimations]; _refleshView.layer.transform = CATransform3DIdentity; [UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; [UIView animateWithDuration:0.35f animations:^{ UIEdgeInsets inset = _scrollView.contentInset; inset.top = _upInset; _scrollView.contentInset = inset; if (_scrollView.contentOffset.y == -_upInset && _slimeMissWhenGoingBack) { self.alpha = 0.0f; } } completion:^(BOOL finished) { _broken = NO; _slime.hidden = NO; _refleshView.hidden = NO; self.refreshRemind.text = @""; self.refreshRemindPicView.hidden = YES; }]; }}- (void)startRefreshWithExpansion{ if (self.type == WaterRefreshTypeOnlyLoadMore || self.type == WaterRefreshTypeNone) { return; } if (self.isRefreshing) { return; } [UIView animateWithDuration:DURIATION_ANIMATE animations:^() { UIEdgeInsets inset = _scrollView.contentInset; inset.top = _upInset + _dragingHeight; _scrollView.contentInset = inset; [_scrollView setContentOffset:CGPointMake(_scrollView.contentOffset.x, -_scrollView.contentInset.top) animated:NO]; }]; [self startRefresh];}-(void)startRefreshWithExpansionWithoutDelegate{ if (self.type == WaterRefreshTypeOnlyLoadMore || self.type == WaterRefreshTypeNone) { return; } if (self.isRefreshing) { return; } [UIView animateWithDuration:DURIATION_ANIMATE animations:^() { UIEdgeInsets inset = _scrollView.contentInset; inset.top = _upInset + _dragingHeight; _scrollView.contentInset = inset; [_scrollView setContentOffset:CGPointMake(_scrollView.contentOffset.x, -_scrollView.contentInset.top) animated:NO]; } completion:^(BOOL finished) { }]; self.isRefreshing = YES;}- (void)startRefresh{ self.isRefreshing = YES; if ([self.refreshDelegate respondsToSelector:@selector(slimeRefreshStartRefresh:)]) { [self.refreshDelegate slimeRefreshStartRefresh:self]; }}- (void)pullApart:(WaterRefreshLoadMoreView*)refreshView{ self.broken = YES; _unmissSlime = YES; [self startRefresh];}- (void)endRefreshWithRemindsWords:(NSString *)remind remindImage:(UIImage *)remindImage{ if (self.type == WaterRefreshTypeOnlyLoadMore || self.type == WaterRefreshTypeNone ) { return; } if (self.isRefreshing && self.endRefreshWithRemind == NO) { self.refreshRemindWord = remind; self.refreshRemindPicView.image = remindImage; self.endRefreshWithRemind = YES; if (self.endAnimation == YES) { [self restore]; } }}- (void)showRemindWordAndClear;{ if (!self.refreshRemindWord || [self.refreshRemindWord isEqualToString:@""]) { [self collapse]; return; } self.refreshRemind.hidden = NO; self.refreshRemind.text = self.refreshRemindWord; self.refreshRemindWord = nil; [self performSelector:@selector(collapse) withObject:nil afterDelay:0.5f]; }- (void)configRefreshPicViewPositionWithWord:(NSString *)word{ if (word && ![word isEqualToString:@""]) { // 如果有提供的文字就做左偏移 //self.refreshRemindPicView.hidden = NO; self.refreshRemindPicView.alpha = 1.0f; CGSize size = [word sizeWithFont:self.refreshRemind.font constrainedToSize:CGSizeMake(self.bounds.size.width, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping]; CGRect rect = self.refreshRemind.frame; rect.size.width = size.width; rect.size.height = size.height; self.refreshRemind.frame = rect; self.refreshRemind.center = _slime.startPoint; self.refreshRemindPicView.center = CGPointMake(self.refreshRemind.frame.origin.x - kDistanceFromRemind, self.refreshRemind.center.y); [self alignmentWithView:self.refreshRemindPicView lable:self.refreshRemind distance:kDistanceFromRemind totalWidth:self.scrollView.frame.size.width]; } else { //还原 //self.refreshRemindPicView.hidden = NO; self.refreshRemindPicView.alpha = 1.0f; self.refreshRemindPicView.center = _slime.startPoint; }}- (void)restore{ _oldLength = 0.0f; _slime.toPoint = _slime.startPoint; [_activityIndicatorView.layer removeAllAnimations]; [UIView setAnimationCurve:UIViewAnimationCurveEaseIn]; [UIView animateWithDuration:0.3f animations:^{ _activityIndicatorView.layer.transform = CATransform3DRotate(CATransform3DMakeScale(0.01f, 0.01f, 0.1f), -M_PI, 0, 0, 1); } completion:^(BOOL finished) { [self relayoutLoadMoreViewAndInset]; if (self.refreshRemindPicView.image) { self.refreshRemindPicView.hidden = NO; [self configRefreshPicViewPositionWithWord:self.refreshRemindWord]; } else { [self alignmentWithView:nil lable:self.refreshRemind distance:0.0f totalWidth:self.scrollView.frame.size.width]; } if (self.refreshRemindWord) { self.refreshRemind.hidden = NO; [self showRemindWordAndClear]; } else { [self collapse]; } }];}- (void)collapse{ if (_isRefreshing == NO) { return; } [self setIsRefreshing:NO]; self.endRefreshWithRemind = NO; _slime.state = SRSlimeStateNormal; if ([self.refreshDelegate respondsToSelector:@selector(slimeRefreshEndRefresh:)]) { [self.refreshDelegate slimeRefreshEndRefresh:self]; }}#pragma mark - Observer handle- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ if (context == &scrollViewObservanceContext) { // handle change if ([keyPath isEqualToString:KEYPATH_CONTENTOFFSET]) { [self scrollViewDidScroll]; if (self.scrollView.dragging == YES && self.lastDragScroll == NO) { self.lastDragScroll = YES; } else if (self.scrollView.dragging == NO && self.lastDragScroll == YES) { self.lastDragScroll = NO; [self scrollViewDidEndDraging]; } } } if (context == &scrollViewContentSizeContext) { if ([keyPath isEqualToString:KEYPATH_CONTENTSIZE]) { [self configLoadMoreHide]; [self relayoutLoadMoreViewAndInset]; } }}#pragma mark - Animation Delegate- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ self.endAnimation = YES; if (self.endRefreshWithRemind == YES) { self.endRefreshWithRemind = NO; self.endAnimation = NO; [self restore]; }}- (void)animationDidStart:(CAAnimation *)anim{ self.endAnimation = NO;}@end
源码用的图片:
使用源码:
//// ViewController.m// Refresh//// Created by YouXianMing on 14/11/21.// Copyright (c) 2014年 YouXianMing. All rights reserved.//#import "ViewController.h"#import "WaterRefreshLoadMoreView.h"@interface ViewController ()@property (nonatomic, strong) UITableView *tableView;@property (nonatomic, strong) WaterRefreshLoadMoreView *refreshLoadMoreView;@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 64, 320, 400) style:UITableViewStylePlain]; [self.view addSubview:self.tableView]; _refreshLoadMoreView = [[WaterRefreshLoadMoreView alloc] initWithWithType:WaterRefreshTypeOnlyRefresh]; _refreshLoadMoreView.scrollView = self.tableView;}- (void)dealloc { [_refreshLoadMoreView deallocWithCloseConnect];}@end
上拉加载下拉刷新控件WaterRefreshLoadMoreView
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。