周末仿写了半糖的下拉刷新,学了两句法语
- C'est La Vie
- La Vie est belle
C'est La Vie 通常是用在较为消极的事情发生时,用于自我安慰或自我解嘲,鼓励自己或他人即使遇到了再大的难处,也要坦然笑对生活。哈哈,鸡汤一下开始正文。
示例
-
半糖
-
PDPullToRefresh
思路
PDPullToRefresh是给UIScrollView加的分类,包括PDHeaderRefreshView和PDFooterRefreshView ,整个刷新过程可分为两部分
- 下拉时 - C'est La Vie 动画
- 刷新时 - La Vie est belle 动画
C'est La Vie 动画
首先得拿到C'est La Vie的字形,这里用到了CoreText,拿到字形后添加到layer.path上显示
CGMutablePathRef letters = CGPathCreateMutable();
CTFontRef font = CTFontCreateWithName(CFSTR("HelveticaNeue-UltraLight"), pFontSize, NULL);
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
(__bridge id)font, kCTFontAttributeName,
nil];
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:animationString
attributes:attrs];
CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)attrString);
CFArrayRef runArray = CTLineGetGlyphRuns(line);
// for each RUN
for (CFIndex runIndex = 0; runIndex < CFArrayGetCount(runArray); runIndex++)
{
// Get FONT for this run
CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runArray, runIndex);
CTFontRef runFont = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName);
// for each GLYPH in run
for (CFIndex runGlyphIndex = 0; runGlyphIndex < CTRunGetGlyphCount(run); runGlyphIndex++)
{
// get Glyph & Glyph-data
CFRange thisGlyphRange = CFRangeMake(runGlyphIndex, 1);
CGGlyph glyph;
CGPoint position;
CTRunGetGlyphs(run, thisGlyphRange, &glyph);
CTRunGetPositions(run, thisGlyphRange, &position);
// Get PATH of outline
{
CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyph, NULL);
CGAffineTransform t = CGAffineTransformMakeTranslation(position.x, position.y);
CGPathAddPath(letters, &t, letter);
CGPathRelease(letter);
}
}
}
CFRelease(line);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointZero];
[path appendPath:[UIBezierPath bezierPathWithCGPath:letters]];
CGPathRelease(letters);
CFRelease(font);
CAShapeLayer *pathLayer = [CAShapeLayer layer];
pathLayer.frame = self.animationLayer.bounds;
pathLayer.bounds = CGPathGetBoundingBox(path.CGPath);
pathLayer.geometryFlipped = YES;
pathLayer.path = path.CGPath;
pathLayer.strokeColor = [UIColor colorWithRed:234.0/255 green:84.0/255 blue:87.0/255 alpha:1].CGColor;
pathLayer.fillColor = nil;
pathLayer.lineWidth = 1.0f;
pathLayer.lineJoin = kCALineJoinBevel;
然后用KVO监听ScrollView的contentOffset属性,与pathLayer的strokeEnd关联起来,C'est La Vie就可以随着下拉做动画啦。
La Vie est belle 动画
La Vie est belle与C'est La Vie的动画不同,它是一直闪动着的,还是先拿到La Vie est belle的字形,这里用CAGradientLayer可以方便的处理颜色渐变。
CAGradientLayer *gradientLayer = (CAGradientLayer *)self.gradientLayer;
if([gradientLayer animationForKey:kAnimationKey] == nil)
{
// 通过不断改变渐变的起止范围,来实现光晕效果
CABasicAnimation *startPointAnimation = [CABasicAnimation animationWithKeyPath:gradientStartPointKey];
startPointAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 0)];
startPointAnimation.timingFunction = [CAMediaTimingFunction functionWithName:_animationPacing];
CABasicAnimation *endPointAnimation = [CABasicAnimation animationWithKeyPath:gradientEndPointKey];
endPointAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(1 + pHaloWidth, 0)];
endPointAnimation.timingFunction = [CAMediaTimingFunction functionWithName:_animationPacing];
CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = @[startPointAnimation, endPointAnimation];
group.duration = pHaloDuration;
group.timingFunction = [CAMediaTimingFunction functionWithName:_animationPacing];
group.repeatCount = HUGE_VALF;
[gradientLayer addAnimation:group forKey:kAnimationKey];
}
使用
安装
- 添加
pod 'PDPullToRefresh'
到你的 Podfile ,然后pod install
。 - 手动添加到你的Xcode项目中,
#import "PDPullToRefresh.h"
。
添加下拉刷新
[tableView pd_addHeaderRefreshWithNavigationBar:YES andActionHandler:^{
// prepend data to dataSource, insert cells at top of table view
// call [tableView.pdHeaderRefreshView stopRefreshing] when done
}];
添加上拉刷新
[tableView pd_addFooterRefreshWithNavigationBar:YES andActionHandler:^{
// prepend data to dataSource, insert cells at top of table view
// call [tableView.pdFooterRefreshView stopRefreshing] when done
}];
立即刷新
[tableView.pdHeaderRefreshView startRefreshing];
自定义
目前仅支持下拉距离自定义,默认高度为80
@property (nonatomic, assign) CGFloat pdHeaderRefreshViewHeight;
@property (nonatomic, assign) CGFloat pdFooterRefreshViewHeight;
最后
附上Github地址,外加感谢半塘、SVPullToRefresh对我的启发。