上拉加载下拉刷新控件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.h

//
// 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 / ,
frame.size.height / );
_viscous = 45.0f; // 拉扯长度
_radius = 17.0f; // 拉扯物体半径
_bodyColor = [[UIColor grayColor] colorWithAlphaComponent:0.45f];
_skinColor = [[UIColor blackColor] colorWithAlphaComponent:0.12f];
_lineWith = 1.0;
_shadowBlur = ;
_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/ + (M_PI/) * percent;
CGPoint sp1 = pointLineToArc(_startPoint, _toPoint, angle1, startRadius),
sp2 = pointLineToArc(_startPoint, _toPoint, -angle1, startRadius),
ep1 = pointLineToArc(_toPoint, _startPoint, M_PI/, endRadius),
ep2 = pointLineToArc(_toPoint, _startPoint, -M_PI/, endRadius);
#define kMiddleP 0.6
CGPoint mp1 = CGPointMake(sp2.x*kMiddleP + ep1.x*(-kMiddleP), sp2.y*kMiddleP + ep1.y*(-kMiddleP)),
mp2 = CGPointMake(sp1.x*kMiddleP + ep2.x*(-kMiddleP), sp1.y*kMiddleP + ep2.y*(-kMiddleP)),
mm = CGPointMake((mp1.x + mp2.x)/, (mp1.y + mp2.y)/);
float p = distansBetween(mp1, mp2) / / endRadius * (0.9 + percent/);
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* - 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/
endAngle:angleS + M_PI*/
clockwise:YES];
[path addQuadCurveToPoint:sp1
controlPoint:mp2]; return path;
} - (void)drawRect:(CGRect)rect
{
switch (_state) {
case SRSlimeStateNormal:
{
float percent = - distansBetween(_startPoint , _toPoint) / _viscous;
if (percent == ) {
CGContextRef context = UIGraphicsGetCurrentContext();
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(_startPoint.x - _radius, _startPoint.y - _radius, *_radius, *_radius) cornerRadius:_radius];
[self setContext:context path:path];
CGContextDrawPath(context, kCGPathFillStroke);
}else {
CGFloat startRadius = _radius * (kStartTo + ( - kStartTo) * percent);
CGFloat endRadius = _radius * (kEndTo + ( - 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 <= ) {
_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 = - p;
float r = _radius * p; if (p > 0.01) {
CGFloat startRadius = r * (kStartTo + ( - kStartTo) * percent);
CGContextRef context = UIGraphicsGetCurrentContext(); CGFloat endRadius = r * (kEndTo + ( - kEndTo) * percent) * ( + percent / );
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

SRSlimeView.m

/**
* 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.h

//
// 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.0f static 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(, , [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 / , height / );
[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(, , 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: context:&scrollViewObservanceContext];
[self.scrollView addObserver:self forKeyPath:KEYPATH_CONTENTSIZE options: 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(, 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 / , self.loadMoreView.frame.size.height / );
[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 / , _dragingHeight / );
}
_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 = ;
}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, );
}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, );
}
_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 * -, );
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 + ) {
[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 + ) {
[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 : ;
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(, 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, , , )],
[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.6, 1.6, )],
[NSValue valueWithCATransform3D:CATransform3DIdentity], nil];
aniamtion.keyTimes = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:],
[NSNumber numberWithFloat:0.6],
[NSNumber numberWithFloat:], 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, , , );
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, , , );
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 = ;
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 ? : 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 / , self.loadMoreView.frame.size.height / );
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 / , self.loadMoreView.frame.size.height / );
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 / , self.loadMoreView.frame.size.height / );
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) / ;
view.center = CGPointMake(left + view.frame.size.width / , view.center.y);
label.center = CGPointMake(view.center.x + view.frame.size.width / + distance + label.frame.size.width / , 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, , , )],
[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.6, 1.6, )],
[NSValue valueWithCATransform3D:CATransform3DIdentity], nil];
aniamtion.keyTimes = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:],
[NSNumber numberWithFloat:0.6],
[NSNumber numberWithFloat:], 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, , , );
} 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

WaterRefreshLoadMoreView.m

源码用的图片:

使用源码:

//
// 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(, , , )
style:UITableViewStylePlain];
[self.view addSubview:self.tableView]; _refreshLoadMoreView = [[WaterRefreshLoadMoreView alloc] initWithWithType:WaterRefreshTypeOnlyRefresh];
_refreshLoadMoreView.scrollView = self.tableView;
} - (void)dealloc {
[_refreshLoadMoreView deallocWithCloseConnect];
} @end

上拉加载下拉刷新控件WaterRefreshLoadMoreView的更多相关文章

  1. Vue mint ui用在消息页面上拉加载下拉刷新loadmore 标记

    之前总结过一个页面存在多个下拉加载的处理方式,今天再来说一下在消息页面的上拉加载和下拉刷新,基本上每个app都会有消息页面,会遇到这个需求 需求:每次加载十条数据,上拉加载下拉刷新,并且没有点击查看过 ...

  2. RecyclerView 上拉加载下拉刷新

    RecyclerView 上拉加载下拉刷新 <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/teach_s ...

  3. APICloud上啦加载下拉刷新模块

    apicloud有自带的上啦加载下拉刷新,当让也可以用第三方或者在模块库里面找一个使用 一.下拉刷新,一下代码写在 apiready = function (){} 里面 apiready = fun ...

  4. 微信小程序上拉加载下拉刷新

    微信小程序实现上拉加载下拉刷新 使用小程序默认提供方法. (1). 在xxx.json 中开启下拉刷新,需要设置backgroundColor,或者是backgroundTextStyle ,因为加载 ...

  5. mui scroll和上拉加载/下拉刷新

    mui中 scroll和上拉加载/下拉刷新同时存在会出现两个滚动条 把/*   */ /* //mui页面鼠标拖动代码: mui('.mui-scroll-wrapper').scroll({ dec ...

  6. Flutter上拉加载下拉刷新---flutter_easyrefresh

    前言 Flutter默认不支持上拉加载,下拉刷新也仅仅支持Material的一种样式.Android开发使用过SmartRefreshLayout的小伙伴都知道这是一个强大的刷新UI库,集成了很多出色 ...

  7. SwipeRefreshLayout实现上拉加载下拉刷新

    package com.example.swiperefreshlayoutdemo; import java.util.ArrayList;import java.util.HashMap; imp ...

  8. MJRefresh(上拉加载下拉刷新)

    整理自:https://github.com/CoderMJLee/MJRefresh#%E6%94%AF%E6%8C%81%E5%93%AA%E4%BA%9B%E6%8E%A7%E4%BB%B6%E ...

  9. 利用iscroll实现上拉加载下拉刷新

    1.首先引用isScroll插件 说明:页面加载时初始化isScroll,然后调用pullDownAction()和pullUpAction(),每次切换tab时,只需要对pullDownAction ...

随机推荐

  1. vuex中怎么把‘库’中的状态对象赋值给内部对象(三种方法)

    一.通过computed的计算属性直接赋值 import store from '@/store/store' export default{ name: 'count', data(){ retur ...

  2. 任务四十:UI组件之日历组件(一)

    任务四十:UI组件之日历组件(一) 面向人群: 有一定基础的同学 难度: 中 重要说明 百度前端技术学院的课程任务是由百度前端工程师专为对前端不同掌握程度的同学设计.我们尽力保证课程内容的质量以及学习 ...

  3. 自己实现一个双向绑定的Vue

    我们知道双向绑定是Vue的核心之一,接下来我们自己仿照Vue实现一个基本的功能. 项目代码在GitHub上: https://github.com/zhangKunUserGit/zk-vue

  4. Css3盒子尺寸

    box-sizing属性 用来改变盒模式中的宽度和高度默认的计算方式. box-sizing: 1.content-box(默认值): 宽度和高度只包含内容区域 2.border-box: 宽度和高度 ...

  5. CentOS如何挂载U盘(待更新)

    使用Linux系统时,经常需要用到U盘,下面介绍以下如何再CentOS上挂载U盘. 首先,切换到root用户. 首先,切换到root用户. 首先,切换到root用户. 重要的事情说三遍,很多同学都说, ...

  6. 请比较throw 合throws的区别

    throw语句用在方法体内,表示抛出异常.throws语句用在方法声明的后面,表示再抛出异常,由该方法的调用者来处理.throws主要声明这个方法会抛出这种类型的异常,使它的调用者知道要捕获这个异常. ...

  7. 15、springboot访问html文件

    在pom.xml加入 <parent> <groupId>org.springframework.boot</groupId> <artifactId> ...

  8. Python爬虫初识

    本文章是对网易云课堂中的Python网络爬虫实战课程进行总结.感兴趣的朋友可以观看视频课程.课程地址 爬虫简介 一段自动抓取互联网信息的程序 非结构化数据 没有固定的数据格式,如网页资料. 必须通过E ...

  9. whistle替代Fiddler调试远程服务器代码使用教程

    前沿 之前在window下开发的同学大部分都是使用Fiddler代理工具做远程调试,自从换了Mac后也想找个代替工具调试,查询了下大概都比较推荐两款:Charles 和 Whistle .不过Char ...

  10. python中垃圾回收机制

    Python垃圾回收机制详解   一.垃圾回收机制 Python中的垃圾回收是以引用计数为主,分代收集为辅.引用计数的缺陷是循环引用的问题.在Python中,如果一个对象的引用数为0,Python虚拟 ...