#import <UIKit/UIKit.h> @protocol PieViewDelegate <NSObject> @required -(void)show; @end @protocol PieViewSourceDelegate <NSObject> @required -(NSInteger)NumberOfParts; -(NSInteger)PartValue:(NSInteger) Index; -(UIColor*)PartColor:(NSInteger) Index; @end @interface PieView : UIView @property (nonatomic,assign) CGFloat Radius; @property (nonatomic,assign) CGFloat BeginAngle; @property (nonatomic,assign) CFTimeInterval CycleTime; @property (nonatomic,weak) id<PieViewSourceDelegate> SourceDelegate; -(instancetype)initWithFrame:(CGRect)frame; -(void)Refresh; -(void)ReCovery; @end
#import "PieView.h" #import "PieLayer.h" @implementation PieView { @private NSTimer* _timer; NSMutableArray *_animations; UIFont* _TextFont; } -(instancetype)initWithFrame:(CGRect)frame { if ([super initWithFrame:frame]) { _animations = [NSMutableArray arrayWithCapacity:5]; _timer = nil; self.Radius = MIN(frame.size.width / 2, frame.size.height / 2); _TextFont = [UIFont boldSystemFontOfSize:12.0]; self.BeginAngle = 0; self.CycleTime = 1; } return self; } -(void)ReCovery { NSInteger iCounts = self.layer.sublayers.count; if (iCounts == 0) return; __block stPieAngleSet sSet; sSet.BeginAngle = self.BeginAngle; sSet.StartAngle = 0.0; sSet.EndAngle = 0.0; [self.layer.sublayers enumerateObjectsUsingBlock:^(PieLayer* obj, NSUInteger idx, BOOL *stop) { [CATransaction begin]; obj.Angles = sSet; [obj CreateAnimations]; [CATransaction commit]; }]; } -(void)Refresh { if (!self.SourceDelegate) return; /*删除所有的layer,直接用self.layer.sublayers还有错误,和线程访问相关*/ NSArray* arrRecovery = [NSArray arrayWithArray:self.layer.sublayers]; if (arrRecovery.count > 0) { [arrRecovery enumerateObjectsUsingBlock:^(CAShapeLayer* obj, NSUInteger idx, BOOL *stop) { [obj removeFromSuperlayer]; }]; } /*获取数目*/ NSInteger iPartCount = [self.SourceDelegate NumberOfParts]; NSInteger iValues[iPartCount]; NSInteger iSum = 0; /*获取值*/ for (NSInteger i = 0; i < iPartCount; i++) { iValues[i] = [self.SourceDelegate PartValue:i]; iSum += iValues[i]; } if (iSum == 0) return; /*计算角度,弧度表示*/ CGFloat fAngles[iPartCount]; for (NSInteger i = 0; i < iPartCount; i++) { fAngles[i] = M_PI * 2 * iValues[i] / iSum; } stPieAngleSet sSets[iPartCount]; CGFloat StartAngle = 0.0; for (NSInteger i = 0; i < iPartCount; i++) { sSets[i].BeginAngle = self.BeginAngle; sSets[i].StartAngle = StartAngle; sSets[i].EndAngle = StartAngle + fAngles[i]; StartAngle += fAngles[i]; } /*创建layer*/ for (NSInteger i = 0; i < iPartCount; i++) { [CATransaction begin];/*认为可以不用加,因为创建了还看不到呢*/ PieLayer* Layer = [PieLayer layer]; [self.layer addSublayer:Layer]; Layer.Angles = sSets[i]; Layer.CADelegate = self; Layer.fillColor = [[self.SourceDelegate PartColor:i] CGColor]; Layer.CycleTime = self.CycleTime; Layer.Value = [NSString stringWithFormat:@"%ld", iValues[i]]; Layer.TextFont = _TextFont; [Layer CreateAnimations]; [CATransaction commit]; } } -(void)TimerFired:(NSTimer*) timer { [self.layer.sublayers enumerateObjectsUsingBlock:^(PieLayer* obj, NSUInteger idx, BOOL *stop) { NSNumber* StartAngle = [[obj presentationLayer] valueForKey:SAngle]; NSNumber* EndAngle = [[obj presentationLayer] valueForKey:EAngle]; CGFloat S = [StartAngle floatValue]; CGFloat E = [EndAngle floatValue]; CGPoint _Center = self.layer.position; CGMutablePathRef path = CGPathCreateMutable(); CGPathMoveToPoint(path, NULL, _Center.x, _Center.y); CGPathAddArc(path, NULL, _Center.x, _Center.y, self.Radius, S, E, 0); CGPathCloseSubpath(path); [obj setPath:path]; [CATransaction setDisableActions:YES]; CALayer* textLayer = [[obj sublayers] objectAtIndex:0]; CGFloat M = (S + E) / 2; CGSize size = [@"0" sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:obj.TextFont,NSFontAttributeName, nil]]; [textLayer setBounds:CGRectMake(0, 0, size.width * 2, size.height)]; [textLayer setPosition:CGPointMake(_Center.x + (self.Radius / 2 * cos(M)), _Center.y + (self.Radius / 2 * sin(M)))]; [CATransaction setDisableActions:NO]; }]; } -(void)animationDidStart:(CAAnimation *)anim { if (!_timer) { static float timeInterval = 1.0/60.0; _timer = [NSTimer timerWithTimeInterval:timeInterval target:self selector:@selector(TimerFired:) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; } [_animations addObject:anim]; } -(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { [_animations removeObject:anim]; if (_animations.count == 0) { [_timer invalidate]; _timer = nil; } } @end
#import <QuartzCore/QuartzCore.h> #import <UIKit/UIKit.h> #define SAngle @"StartAngle" #define EAngle @"EndAngle" typedef struct { CGFloat BeginAngle; CGFloat StartAngle; CGFloat EndAngle; }stPieAngleSet; @interface PieLayer : CAShapeLayer @property(nonatomic,assign) stPieAngleSet Angles; @property(nonatomic,weak) id CADelegate; @property(nonatomic,assign) CFTimeInterval CycleTime; @property(nonatomic,strong,setter=SetFont:) UIFont* TextFont; @property(nonatomic,strong,setter=SetStrValue:) NSString* Value; -(void)CreateAnimations; -(void)SetFont:(UIFont*) font; -(void)SetStrValue:(NSString *)Value; @end
#import "PieLayer.h" @implementation PieLayer -(void)SetStrValue:(NSString *)Value { _Value = Value; CATextLayer* TextLayer = [self.sublayers objectAtIndex:0]; [TextLayer setString:_Value]; } -(void)SetFont:(UIFont *)font { CATextLayer* TextLayer = [self.sublayers objectAtIndex:0]; _TextFont = font; /*字体的处理,没有理解,但是没有还真不行*/ CGFontRef FontRef = nil; if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) { FontRef = CGFontCreateCopyWithVariations((__bridge CGFontRef)(_TextFont), (__bridge CFDictionaryRef)(@{})); } else { FontRef = CGFontCreateWithFontName((__bridge CFStringRef)[_TextFont fontName]); } if (FontRef) { [TextLayer setFont:FontRef]; CFRelease(FontRef); } [TextLayer setFontSize:self.TextFont.pointSize]; [TextLayer setAlignmentMode:kCAAlignmentCenter]; } -(void)CreateAnimations { /*创建两组动画,这里的动画没起作用,只提供了2个值,然后进行setPath*/ CABasicAnimation* base1 = [CABasicAnimation animation]; NSNumber* S = [NSNumber numberWithFloat:self.Angles.BeginAngle]; NSNumber* E = [NSNumber numberWithFloat:self.Angles.BeginAngle + self.Angles.StartAngle]; NSNumber* CS = [[self presentationLayer] valueForKey:SAngle]; if (!CS) CS = S; [base1 setFromValue:CS]; [base1 setToValue:E]; [base1 setDuration:self.CycleTime]; [base1 setDelegate:self.CADelegate]; [base1 setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]]; [self addAnimation:base1 forKey:SAngle]; [self setValue:E forKey:SAngle]; CABasicAnimation* base2 = [CABasicAnimation animation]; S = [NSNumber numberWithFloat:self.Angles.BeginAngle]; E = [NSNumber numberWithFloat:self.Angles.BeginAngle + self.Angles.EndAngle]; CS = [[self presentationLayer] valueForKey:EAngle]; if (!CS) CS = S; [base2 setFromValue:CS]; [base2 setToValue:E]; [base2 setDuration:self.CycleTime]; [base2 setDelegate:self.CADelegate]; [base2 setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]]; [self setValue:E forKey:EAngle]; [self addAnimation:base2 forKey:EAngle]; } -(instancetype)init { if (self = [super init]) { CATextLayer* TextLayer = [CATextLayer layer]; [self addSublayer:TextLayer]; TextLayer.contentsScale =[[UIScreen mainScreen] scale]; /*先给个默认的背景吧,好看点儿~~*/ [TextLayer setBackgroundColor:[UIColor clearColor].CGColor]; [TextLayer setShadowColor:[UIColor greenColor].CGColor]; [TextLayer setShadowOffset:CGSizeZero]; [TextLayer setShadowRadius:3.0]; [TextLayer setShadowOpacity:1.0]; [TextLayer setForegroundColor:[UIColor redColor].CGColor]; } return self; } @end调用部分
#import "ViewController.h" @interface ViewController () @property (nonatomic, strong) PieView* LeftPie; @end @implementation ViewController { Boolean _IsShowState; } - (void)viewDidLoad { [super viewDidLoad]; self.LeftPie = [[PieView alloc] initWithFrame:CGRectMake(20, 20, 100, 100)]; _IsShowState = NO; [self.view addSubview:self.LeftPie]; self.LeftPie.CycleTime = 2; [self.LeftPie setSourceDelegate:self]; [self.LeftPie setBeginAngle:M_PI / 2]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { if (_IsShowState) { [self.LeftPie ReCovery]; } else { [self.LeftPie Refresh]; }; _IsShowState = !_IsShowState; } -(NSInteger)NumberOfParts { return 5; } -(NSInteger)PartValue:(NSInteger)Index { switch (Index) { case 0: return 20; case 1: return 10; case 2: return 30; case 3: return 40; case 4: return 25; } return 20; } -(UIColor*)PartColor:(NSInteger)Index { switch (Index) { case 0: return [UIColor grayColor]; case 1: return [UIColor redColor]; case 2: return [UIColor darkGrayColor]; case 3: return [UIColor blueColor]; case 4: return [UIColor brownColor]; } return [UIColor clearColor]; } @end