You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
6.8 KiB
232 lines
6.8 KiB
// |
|
// XHWaterDropRefresh.m |
|
// XHPathCover |
|
// |
|
// Created by 曾 宪华 on 14-2-7. |
|
// Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved. |
|
// |
|
|
|
#import "XHWaterDropRefresh.h" |
|
#import "XHSoundManager.h" |
|
|
|
@interface XHWaterDropRefresh ()<CAAnimationDelegate> { |
|
BOOL _isRefresh; |
|
} |
|
|
|
@property (nonatomic, strong) CAShapeLayer *shapeLayer; |
|
@property (nonatomic, strong) CAShapeLayer *lineLayer; |
|
@property (nonatomic, strong) UIImageView *refreshView; |
|
|
|
|
|
@property (nonatomic, strong) NSTimer *timer; |
|
|
|
@end |
|
|
|
@implementation XHWaterDropRefresh |
|
|
|
#pragma mark - Propertys |
|
|
|
- (BOOL)isRefreshing { |
|
return _isRefresh; |
|
} |
|
|
|
|
|
#pragma mark - Life cycle |
|
|
|
- (id)initWithFrame:(CGRect)frame |
|
{ |
|
self = [super initWithFrame:frame]; |
|
if (self) { |
|
// Initialization code |
|
[self _setup]; |
|
} |
|
return self; |
|
} |
|
|
|
- (id)initWithCoder:(NSCoder *)aDecoder |
|
{ |
|
self = [super initWithCoder:aDecoder]; |
|
if(self) |
|
{ |
|
[self _setup]; |
|
} |
|
return self; |
|
} |
|
|
|
- (void)dealloc { |
|
self.refreshCircleImage = nil; |
|
|
|
self.shapeLayer = nil; |
|
self.lineLayer = nil; |
|
self.refreshView = nil; |
|
} |
|
|
|
- (void)_setup { |
|
self.deformationLength = 0.4; |
|
self.maxOffset = 70; // 改变最大拉断距离 |
|
self.radius = 5.; // 改变圆圈的半径 |
|
self.offsetHeight = 20; // 改变线条的长度 |
|
|
|
CGRect frame = self.frame; |
|
frame.size = CGSizeMake(30, 100); //固定 30 * 100 为什么要固定本身的大小呢? |
|
self.frame = frame; |
|
|
|
_lineLayer = [CAShapeLayer layer]; |
|
_lineLayer.fillColor = [UIColor colorWithRed:222./255. green:216./255. blue:211./255. alpha:0.5].CGColor; |
|
[self.layer addSublayer:_lineLayer]; |
|
|
|
|
|
_shapeLayer = [CAShapeLayer layer]; |
|
_shapeLayer.fillColor = [UIColor colorWithRed:222./255. green:216./255. blue:211./255. alpha:1].CGColor; |
|
_shapeLayer.strokeColor = [[UIColor whiteColor] CGColor]; |
|
_shapeLayer.lineWidth = 2; |
|
[self.layer addSublayer:_shapeLayer]; |
|
|
|
self.currentOffset = 0; |
|
} |
|
|
|
#pragma mark - Publish Api |
|
|
|
- (void)stopRefresh { |
|
_isRefresh = NO; |
|
|
|
CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"opacity"]; |
|
anim.fromValue = @(1); |
|
anim.toValue = @(0); |
|
anim.duration = 0.2; |
|
anim.delegate = self; |
|
[_refreshView.layer addAnimation:anim forKey:nil]; |
|
_refreshView.layer.opacity = 0; |
|
|
|
|
|
anim = [CABasicAnimation animationWithKeyPath:@"opacity"]; |
|
anim.fromValue = @(0); |
|
anim.toValue = @(1); |
|
anim.beginTime = 0.2; |
|
anim.duration = 0.2; |
|
anim.delegate = self; |
|
[_shapeLayer addAnimation:anim forKey:nil]; |
|
_shapeLayer.opacity = 0; |
|
} |
|
|
|
|
|
- (void)startRefreshAnimation { |
|
if(self.refreshView == nil) { |
|
_refreshView = [[UIImageView alloc] initWithImage:self.refreshCircleImage]; |
|
CGRect refreshViewFrame = _refreshView.frame; |
|
refreshViewFrame.size = CGSizeMake(18, 18); |
|
[self addSubview:_refreshView]; |
|
} |
|
_shapeLayer.opacity = 0; |
|
|
|
_refreshView.center = CGPointMake(15,self.frame.size.height - 20 - _radius); |
|
[_refreshView.layer removeAllAnimations]; |
|
_refreshView.layer.opacity = 1; |
|
|
|
CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; |
|
animation.duration = 1; |
|
animation.fromValue = @0; |
|
animation.toValue = @(M_PI*2); |
|
animation.repeatCount = INT_MAX; |
|
|
|
[_refreshView.layer addAnimation:animation forKey:@"rotation"]; |
|
} |
|
|
|
#pragma mark - CGMutablePathRef Help Method |
|
|
|
- (CGMutablePathRef)createPathWithOffset:(float)currentOffset { |
|
CGMutablePathRef path = CGPathCreateMutable(); |
|
float top = self.frame.size.height - 20 - _radius*2 - currentOffset; |
|
float wdiff = currentOffset * self.deformationLength; // 改变拉断之前,水滴的长度 |
|
|
|
if(currentOffset == 0) { |
|
CGPathAddEllipseInRect(path, NULL, CGRectMake(15-_radius, top, _radius*2, _radius*2)); |
|
} else { |
|
CGPathAddArc(path, NULL, 15, top+_radius, _radius, 0, M_PI, YES); |
|
float bottom = top + wdiff+_radius*2; |
|
if(currentOffset < 10) { |
|
CGPathAddCurveToPoint(path, NULL,15-_radius,bottom,15,bottom, 15,bottom); |
|
CGPathAddCurveToPoint(path, NULL, 15,bottom,15+_radius,bottom, 15+_radius, top+_radius); |
|
} else { |
|
CGPathAddCurveToPoint(path, NULL,15-_radius ,top +_radius, 15 - _radius ,bottom - _radius, 15, bottom); |
|
CGPathAddCurveToPoint(path,NULL, 15 + _radius, bottom - _radius, 15+_radius,top +_radius , 15+_radius, top+_radius); |
|
} |
|
} |
|
CGPathCloseSubpath(path); |
|
|
|
return path; |
|
} |
|
|
|
- (void)setCurrentOffset:(float)currentOffset { |
|
if(_isRefresh) |
|
return; |
|
|
|
[self privateSetCurrentOffset:currentOffset]; |
|
} |
|
|
|
- (void)privateSetCurrentOffset:(float)currentOffset { |
|
currentOffset = currentOffset>0?0:currentOffset; |
|
currentOffset = -currentOffset; |
|
_currentOffset = currentOffset; |
|
if(currentOffset < _maxOffset) { |
|
float wdiff = currentOffset* 0.2; |
|
float top = self.frame.size.height - 20 - _radius*2 - currentOffset; |
|
|
|
CGMutablePathRef path = [self createPathWithOffset:currentOffset]; |
|
_shapeLayer.path = path; |
|
CGPathRelease(path); |
|
|
|
|
|
CGMutablePathRef line = CGPathCreateMutable(); |
|
float w = ((_maxOffset - currentOffset)/_maxOffset) + 1; |
|
CGPathAddRect(line, NULL, CGRectMake(15-w/2, top + wdiff + _radius*2,w, currentOffset-wdiff + self.offsetHeight)); // 最好的+20就是线条的长度 |
|
_lineLayer.path = line; |
|
|
|
self.transform = CGAffineTransformMakeScale(0.8+0.2*(w-1), 1); |
|
} else { |
|
if(self.timer == nil) |
|
{ |
|
_isRefresh = YES; |
|
self.transform = CGAffineTransformIdentity; |
|
self.timer = [NSTimer timerWithTimeInterval:0.02 target:self selector:@selector(resetWater) userInfo:nil repeats:YES]; |
|
[[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; |
|
[_timer fire]; |
|
} |
|
} |
|
} |
|
|
|
- (void)resetWater { |
|
[self privateSetCurrentOffset:-(_currentOffset-(_maxOffset/8))]; |
|
if(_currentOffset == 0) { |
|
[self.timer invalidate]; |
|
self.timer = nil; |
|
|
|
// play refresh stop sound |
|
[[XHSoundManager sharedInstance] playRefreshSound]; |
|
|
|
if(self.handleRefreshEvent != nil) { |
|
self.handleRefreshEvent(); |
|
} |
|
[self startRefreshAnimation]; |
|
} |
|
} |
|
|
|
|
|
- (void)animationDidStop:(CABasicAnimation *)anim finished:(BOOL)flag { |
|
if(anim.beginTime > 0) { |
|
_shapeLayer.opacity = 1; |
|
} else { |
|
[_refreshView.layer removeAllAnimations]; |
|
} |
|
} |
|
|
|
/* |
|
// Only override drawRect: if you perform custom drawing. |
|
// An empty implementation adversely affects performance during animation. |
|
- (void)drawRect:(CGRect)rect |
|
{ |
|
// Drawing code |
|
} |
|
*/ |
|
|
|
@end
|
|
|