[CAAnimation核心动画练习四]饼图1.5 增加值的显示

#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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值