小说绘上架版本
This commit is contained in:
+44
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// WXReaderAnimationLayer.h
|
||||
// WXReader
|
||||
//
|
||||
// Created by Andrew on 2018/6/8.
|
||||
// Copyright © 2018年 Andrew. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM(NSUInteger, WXReaderAnimationState) {
|
||||
WXReaderAnimationStateStoped = 0,
|
||||
WXReaderAnimationStateRunning = 1,
|
||||
WXReaderAnimationStatePausing = 2
|
||||
};
|
||||
|
||||
typedef void(^ReaderAutoReadBlock)(void);
|
||||
|
||||
@interface WXYZ_ReaderAnimationLayer : NSObject
|
||||
|
||||
// 触发自动翻页
|
||||
@property (nonatomic, copy) ReaderAutoReadBlock readerAutoReadBlock;
|
||||
|
||||
- (instancetype)initWithView:(UIView *)keyView;
|
||||
|
||||
// 开始动画
|
||||
- (void)startReadingAnimation;
|
||||
|
||||
//暂停动画
|
||||
- (void)pauseAnimation;
|
||||
|
||||
//继续动画
|
||||
- (void)resumeAnimation;
|
||||
|
||||
// 停止动画
|
||||
- (void)stopAnimation;
|
||||
|
||||
// 重启动画
|
||||
- (void)resetAnimation;
|
||||
|
||||
// 重置时间
|
||||
- (void)resetDuration:(CFTimeInterval)animationDuration;
|
||||
|
||||
@end
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
//
|
||||
// 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
|
||||
Reference in New Issue
Block a user