創(chuàng)建繼承自CALayer
的CircleLayer
類,具體代碼如下
// CircleLayer.h
#import <QuartzCore/QuartzCore.h>
@interface CircleLayer : CALayer
/** 滑塊的進(jìn)度值 */
@property(nonatomic, assign)CGFloat progress;
@end
// CircleLayer.m
#import "CircleLayer.h"
#import <UIKit/UIKit.h>
// 移動(dòng)點(diǎn)的枚舉
typedef enum MovingPoint {
POINT_D,
POINT_B,
} MovingPoint;
// 宏定義
#define outsideRectSize 90
@interface CircleLayer()
/** 外接矩形 */
@property(nonatomic, assign)CGRect outsideRect;
/** 記錄上一次的progress帐我,方便做差得出滑動(dòng)方向 */
@property(nonatomic, assign)CGFloat lastProgress;
/** 實(shí)時(shí)記錄滑動(dòng)方向 */
@property(nonatomic, assign)MovingPoint movePoint;
@end
@implementation CircleLayer
// 初始化滑塊的滑動(dòng)值
- (instancetype)init
{
self = [super init];
if (self) {
self.lastProgress = 0.5;
}
return self;
}
// 初始化動(dòng)畫的Layer
- (instancetype)initWithLayer:(CircleLayer *)layer{
self = [super initWithLayer:layer];
if (self) {
self.progress = layer.progress;
self.outsideRect = layer.outsideRect;
self.lastProgress = layer.lastProgress;
}
return self;
}
// 繪制小球
-(void)drawInContext:(CGContextRef)ctx {
// 外接矩形頂點(diǎn)和控制點(diǎn)的距離坎炼,當(dāng)它為正方形邊長的1/3.6倍時(shí),畫出來的圓弧完美貼合圓形
CGFloat offset = self.outsideRect.size.width / 3.6;
// 外接矩形頂點(diǎn)需要移動(dòng)的距離
CGFloat movedDistance = (self.outsideRect.size.width * 1 / 6) * fabs(self.progress - 0.5) * 2;
// 外接矩形的中心點(diǎn)坐標(biāo)
CGPoint rectCenter = CGPointMake(self.outsideRect.origin.x + self.outsideRect.size.width / 2, self.outsideRect.origin.y + self.outsideRect.size.height / 2);
// 外接矩形頂點(diǎn)的坐標(biāo)
CGPoint pointA = CGPointMake(rectCenter.x, self.outsideRect.origin.y + movedDistance);
CGPoint pointB = CGPointMake(self.movePoint == POINT_D ? rectCenter.x + self.outsideRect.size.width / 2 : rectCenter.x + self.outsideRect.size.width / 2 + movedDistance * 2, rectCenter.y);
CGPoint pointC = CGPointMake(rectCenter.x, rectCenter.y + self.outsideRect.size.height / 2 - movedDistance);
CGPoint pointD = CGPointMake(self.movePoint == POINT_D ? self.outsideRect.origin.x - movedDistance * 2 : self.outsideRect.origin.x, rectCenter.y);
// 外接矩形控制點(diǎn)的坐標(biāo)
CGPoint c1 = CGPointMake(pointA.x + offset, pointA.y);
CGPoint c2 = CGPointMake(pointB.x, self.movePoint == POINT_D ? pointB.y - offset : pointB.y - offset + movedDistance);
CGPoint c3 = CGPointMake(pointB.x, self.movePoint == POINT_D ? pointB.y + offset : pointB.y + offset -movedDistance);
CGPoint c4 = CGPointMake(pointC.x + offset, pointC.y);
CGPoint c5 = CGPointMake(pointC.x - offset, pointC.y);
CGPoint c6 = CGPointMake(pointD.x, self.movePoint == POINT_D ? pointD.y + offset - movedDistance : pointD.y + offset);
CGPoint c7 = CGPointMake(pointD.x, self.movePoint == POINT_D ? pointD.y - offset + movedDistance : pointD.y - offset);
CGPoint c8 = CGPointMake(pointA.x - offset, pointA.y);
// 繪制外接虛線矩形
UIBezierPath *rectPath = [UIBezierPath bezierPathWithRect:self.outsideRect];
CGContextAddPath(ctx, rectPath.CGPath);
CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
CGContextSetLineWidth(ctx, 1.0);
CGFloat dash[] = {5.0, 5.0};
CGContextSetLineDash(ctx, 0.0, dash, 2);
CGContextStrokePath(ctx);
// 圓的邊界
UIBezierPath *ovalPath = [UIBezierPath bezierPath];
[ovalPath moveToPoint:pointA];
[ovalPath addCurveToPoint:pointB controlPoint1:c1 controlPoint2:c2];
[ovalPath addCurveToPoint:pointC controlPoint1:c3 controlPoint2:c4];
[ovalPath addCurveToPoint:pointD controlPoint1:c5 controlPoint2:c6];
[ovalPath addCurveToPoint:pointA controlPoint1:c7 controlPoint2:c8];
[ovalPath closePath];
CGContextAddPath(ctx, ovalPath.CGPath);
CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
CGContextSetFillColorWithColor(ctx, [UIColor redColor].CGColor);
CGContextSetLineDash(ctx, 0, NULL, 0);
CGContextDrawPath(ctx, kCGPathFillStroke);
// 標(biāo)記出每個(gè)點(diǎn)并連線
CGContextSetFillColorWithColor(ctx, [UIColor yellowColor].CGColor);
CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
NSArray *points = @[[NSValue valueWithCGPoint:pointA], [NSValue valueWithCGPoint:pointB], [NSValue valueWithCGPoint:pointC], [NSValue valueWithCGPoint:pointD], [NSValue valueWithCGPoint:c1], [NSValue valueWithCGPoint:c2], [NSValue valueWithCGPoint:c3], [NSValue valueWithCGPoint:c4], [NSValue valueWithCGPoint:c5], [NSValue valueWithCGPoint:c6], [NSValue valueWithCGPoint:c7], [NSValue valueWithCGPoint:c8]];
[self drawPoint:points withContext:ctx];
// 連接輔助線
UIBezierPath *helperline = [UIBezierPath bezierPath];
[helperline moveToPoint:pointA];
[helperline addLineToPoint:c1];
[helperline addLineToPoint:c2];
[helperline addLineToPoint:pointB];
[helperline addLineToPoint:c3];
[helperline addLineToPoint:c4];
[helperline addLineToPoint:pointC];
[helperline addLineToPoint:c5];
[helperline addLineToPoint:c6];
[helperline addLineToPoint:pointD];
[helperline addLineToPoint:c7];
[helperline addLineToPoint:c8];
[helperline closePath];
CGContextAddPath(ctx, helperline.CGPath);
CGFloat dash2[] = {2.0, 2.0};
CGContextSetLineDash(ctx, 0.0, dash2, 2);
CGContextStrokePath(ctx);
}
// 在某個(gè)point位置畫一個(gè)點(diǎn)拦键,方便觀察運(yùn)動(dòng)情況
-(void)drawPoint:(NSArray *)points withContext:(CGContextRef)ctx {
for (NSValue *pointValue in points) {
CGPoint point = [pointValue CGPointValue];
CGContextFillRect(ctx, CGRectMake(point.x - 2, point.y - 2, 4, 4));
}
}
// 設(shè)置滑塊的移動(dòng)位置
-(void)setProgress:(CGFloat)progress {
_progress = progress;
// 外接矩形在左側(cè)谣光,B點(diǎn)動(dòng)
if (progress <= 0.5) {
self.movePoint = POINT_B;
NSLog(@"B點(diǎn)動(dòng)");
} else {
self.movePoint = POINT_D;
NSLog(@"D點(diǎn)動(dòng)");
}
self.lastProgress = progress;
CGFloat origin_x = self.position.x - outsideRectSize / 2 + (progress - 0.5) * (self.frame.size.width - outsideRectSize);
CGFloat origin_y = self.position.y - outsideRectSize / 2;
self.outsideRect = CGRectMake(origin_x, origin_y, outsideRectSize, outsideRectSize);
[self setNeedsDisplay];
}
@end