AnimationCircle
- 用四條曲線拼接出小球的形狀拯坟,逆時(shí)針開始眶诈,分別是弧AB瘸恼,弧BC,弧CD册养,弧DA,每條弧都是兩個(gè)弧頂點(diǎn)加上兩個(gè)控制點(diǎn)压固,一共四個(gè)點(diǎn)繪制的三次貝塞爾曲線球拦。
- 界面布局如圖所示
界面布局圖.png
- 創(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
- 創(chuàng)建繼承自
UIView
的CircleView
類,具體代碼如下// CircleView.h #import <UIKit/UIKit.h> #import "CircleLayer.h" @interface CircleView : UIView /** 圓的layer層 */ @property(nonatomic, strong)CircleLayer *circleLayer; @end // CircleView.m #import "CircleView.h" @implementation CircleView +(Class)layerClass { return [CircleLayer class]; } -(instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.circleLayer = [CircleLayer layer]; self.circleLayer.frame = CGRectMake(0, 0, frame.size.width, frame.size.height); self.circleLayer.contentsScale = [UIScreen mainScreen].scale; [self.layer addSublayer:self.circleLayer]; } return self; } @end
- 控制器代碼如下所示
// ViewController.m #import "ViewController.h" #import "CircleView.h" @interface ViewController () /** 滑塊 */ @property (weak, nonatomic) IBOutlet UISlider *mySlider; /** 滑塊的值 */ @property (weak, nonatomic) IBOutlet UILabel *currentValueLabel; /** 圓視圖 */ @property(nonatomic, strong)CircleView *cv; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self.mySlider addTarget:self action:@selector(valuechange:) forControlEvents:UIControlEventValueChanged]; self.cv = [[CircleView alloc] initWithFrame:CGRectMake(self.view.frame.size.width / 2 - 320 / 2, self.view.frame.size.height / 2 - 320 / 2, 320, 320)]; [self.view addSubview:self.cv]; // 首次進(jìn)入 self.cv.circleLayer.progress = _mySlider.value; } // 滑塊值改變 -(void)valuechange:(UISlider *)sender { self.currentValueLabel.text = [NSString stringWithFormat:@"Current: %f", sender.value]; self.cv.circleLayer.progress = sender.value; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
- 運(yùn)行結(jié)果如圖所示
運(yùn)行結(jié)果圖.gif