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.
183 lines
5.9 KiB
183 lines
5.9 KiB
// |
|
// WXReaderAnimationLayer.m |
|
// WXReader |
|
// |
|
// Created by Andrew on 2018/6/8. |
|
// Copyright © 2018年 Andrew. All rights reserved. |
|
// |
|
|
|
#import "WXYZ_ReaderAnimationLayer.h" |
|
#import "TFReaderSettingHelper.h" |
|
|
|
#define animationKey @"wxreader_animation_layer_key" |
|
|
|
@interface WXYZ_ReaderAnimationLayer () <CAAnimationDelegate> |
|
{ |
|
CFTimeInterval _animationDuration; |
|
UIView *_layerView; |
|
} |
|
|
|
@property (nonatomic, assign) WXReaderAnimationState state; |
|
|
|
@property (nonatomic, strong) CAShapeLayer *shapeLayer; |
|
|
|
@property (nonatomic, strong) CABasicAnimation *pathAnimation; |
|
|
|
@end |
|
|
|
@implementation WXYZ_ReaderAnimationLayer |
|
|
|
- (instancetype)initWithView:(UIView *)keyView |
|
{ |
|
if (self = [super init]) { |
|
_layerView = keyView; |
|
_animationDuration = [[TFReaderSettingHelper sharedManager] getReadSpeed]; |
|
|
|
} |
|
return self; |
|
} |
|
|
|
// 开始动画 |
|
- (void)startReadingAnimation |
|
{ |
|
self.state = WXReaderAnimationStateRunning; |
|
[self.shapeLayer addAnimation:self.pathAnimation forKey:animationKey]; |
|
[_layerView.layer addSublayer:self.shapeLayer]; |
|
} |
|
|
|
//暂停动画 |
|
- (void)pauseAnimation |
|
{ |
|
self.state = WXReaderAnimationStatePausing; |
|
CFTimeInterval pausedTime = [self.shapeLayer convertTime:CACurrentMediaTime() fromLayer:nil]; |
|
self.shapeLayer.speed = 0.0; |
|
self.shapeLayer.timeOffset = pausedTime; |
|
} |
|
|
|
//继续动画 |
|
- (void)resumeAnimation |
|
{ |
|
if (self.state == WXReaderAnimationStateStoped) { |
|
[self startReadingAnimation]; |
|
} |
|
self.state = WXReaderAnimationStateRunning; |
|
CFTimeInterval pausedTime = [self.shapeLayer timeOffset]; |
|
self.shapeLayer.speed = 1.0; |
|
self.shapeLayer.timeOffset = 0.0; |
|
self.shapeLayer.beginTime = 0.0; |
|
CFTimeInterval timeSincePause = [self.shapeLayer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime; |
|
self.shapeLayer.beginTime = timeSincePause; |
|
} |
|
|
|
// 停止动画 |
|
- (void)stopAnimation |
|
{ |
|
self.state = WXReaderAnimationStateStoped; |
|
self.pathAnimation = nil; |
|
[self.shapeLayer removeAnimationForKey:animationKey]; |
|
[self.shapeLayer removeFromSuperlayer]; |
|
self.shapeLayer = nil; |
|
} |
|
|
|
// 重启动画 |
|
- (void)resetAnimation |
|
{ |
|
if (self.state == WXReaderAnimationStateRunning) { |
|
[self resetDuration:_animationDuration]; |
|
} |
|
} |
|
|
|
// 重置时间 |
|
- (void)resetDuration:(CFTimeInterval)animationDuration |
|
{ |
|
_animationDuration = animationDuration; |
|
|
|
if (self.state == WXReaderAnimationStatePausing || self.state == WXReaderAnimationStateStoped) { |
|
[self stopAnimation]; |
|
return; |
|
} |
|
[self startReadingAnimation]; |
|
} |
|
|
|
// 动画代理回调 |
|
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag |
|
{ |
|
if (flag == YES) { |
|
[self.shapeLayer addAnimation:self.pathAnimation forKey:animationKey]; |
|
if (self.state == WXReaderAnimationStateRunning && self.readerAutoReadBlock) { |
|
self.readerAutoReadBlock(); |
|
} |
|
} |
|
} |
|
|
|
- (UIBezierPath *)layerPath |
|
{ |
|
UIBezierPath *path = [UIBezierPath bezierPath]; |
|
if (is_iPhoneX) { |
|
CGFloat lineWidth = 2; |
|
|
|
// 屏幕左上角圆角半径 |
|
CGFloat radius1 = 44; |
|
// 刘海顶部圆角半径 |
|
CGFloat radius2 = 6; |
|
// 刘海底部圆角半径 |
|
CGFloat radius3 = 20; |
|
// 刘海高度 |
|
CGFloat hairHeight = 30; |
|
// 刘海顶部宽度 |
|
CGFloat hairTopWidth = 209; |
|
// 刘海左侧空隙 |
|
CGFloat hairLeftWidth = (SCREEN_WIDTH - hairTopWidth) / 2; |
|
// 刘海右侧空隙 |
|
CGFloat hairRightWidth = hairLeftWidth; |
|
|
|
[path moveToPoint:CGPointMake(lineWidth, radius1)]; |
|
[path addQuadCurveToPoint:CGPointMake(radius1, lineWidth) controlPoint:CGPointMake(lineWidth, lineWidth)]; |
|
|
|
[path addLineToPoint:CGPointMake(hairLeftWidth - radius2, lineWidth)]; |
|
[path addQuadCurveToPoint:CGPointMake(hairLeftWidth - lineWidth, radius2) controlPoint:CGPointMake(hairLeftWidth - lineWidth, lineWidth)]; |
|
|
|
[path addLineToPoint:CGPointMake(hairLeftWidth - lineWidth, hairHeight - radius3)]; |
|
[path addQuadCurveToPoint:CGPointMake(hairLeftWidth + radius3, hairHeight + lineWidth) controlPoint:CGPointMake(hairLeftWidth, hairHeight)]; |
|
|
|
[path addLineToPoint:CGPointMake(SCREEN_WIDTH - hairRightWidth - radius3, hairHeight + lineWidth)]; |
|
[path addQuadCurveToPoint:CGPointMake(SCREEN_WIDTH - hairRightWidth + lineWidth, hairHeight - radius3) controlPoint:CGPointMake(SCREEN_WIDTH - hairRightWidth, hairHeight)]; |
|
|
|
[path addLineToPoint:CGPointMake(SCREEN_WIDTH - hairRightWidth + lineWidth, radius2)]; |
|
[path addQuadCurveToPoint:CGPointMake(SCREEN_WIDTH - hairRightWidth + radius2, lineWidth) controlPoint:CGPointMake(SCREEN_WIDTH - hairRightWidth + lineWidth, lineWidth)]; |
|
|
|
[path addLineToPoint:CGPointMake(SCREEN_WIDTH - radius1, lineWidth)]; |
|
[path addQuadCurveToPoint:CGPointMake(SCREEN_WIDTH - lineWidth, radius1) controlPoint:CGPointMake(SCREEN_WIDTH - lineWidth, lineWidth)]; |
|
} else { |
|
[path moveToPoint:CGPointMake(0, 2)]; |
|
[path addLineToPoint:CGPointMake(SCREEN_WIDTH,2)]; |
|
} |
|
return path; |
|
} |
|
|
|
- (CAShapeLayer *)shapeLayer |
|
{ |
|
if (!_shapeLayer) { |
|
_shapeLayer = [CAShapeLayer layer]; |
|
_shapeLayer.lineWidth = 4; |
|
_shapeLayer.fillColor = [[UIColor clearColor] CGColor]; |
|
_shapeLayer.strokeColor = kColorRGBA(255, 102, 0, 1).CGColor; |
|
_shapeLayer.path = [self layerPath].CGPath; |
|
} |
|
return _shapeLayer; |
|
} |
|
|
|
- (CABasicAnimation *)pathAnimation |
|
{ |
|
if (!_pathAnimation) { |
|
_pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; |
|
_pathAnimation.duration = _animationDuration; |
|
_pathAnimation.repeatCount = 1; |
|
_pathAnimation.delegate = self; |
|
_pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; |
|
_pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; |
|
} |
|
return _pathAnimation; |
|
} |
|
|
|
@end
|
|
|