您的位置:首页 > 其它

[CAAnimation核心动画练习三]饼图1.0的制作

2016-03-10 12:53 323 查看
利用了几个中午的时间,终于有点效果了,得贴出来纪念下~~
#import <QuartzCore/QuartzCore.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;
-(void)CreateAnimations;

@end
#import "PieLayer.h"

@implementation PieLayer

-(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];

}
@end
#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;
}
-(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);
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 CreateAnimations];
[CATransaction commit];
}
}

-(void)TimerFired:(NSTimer*) timer
{
[self.layer.sublayers enumerateObjectsUsingBlock:^(CAShapeLayer* 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];
}];
}

-(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 "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];
// Dispose of any resources that can be recreated.
}
-(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


总结下吧:

1,虽然说属于动画部分,但没有用到动画效果,只是利用动画的中间值进行了layer的填充(自己的理解)

2,这个还不完善,没有值和百分比的显示,也不能点击,更不是三维的,后期继续添加~~

核心思想出自一个ipad程序,里面写的挺复杂的,我做了提炼。工程的名字叫xyPieChart,链接忘了,作者看了请勿喷~~

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: