I have created a pie chart by referring to the link below.https://gist.github.com/glayash/38aa605f99a9666a925d
I want to change the color of the graph depending on the conditions, but it doesn't change during animation.When the time set for the animation time is over, it changes suddenly.Here is an excerpt of some of the codes.
The ViewController is trying to turn the graph red when the param is 100 or less.
ViewController.m
if(param<100){
[_graph setfillColor: [UIColor redColor];
} else{
[_graph setfillColor: [UIColor blueColor];
}
CABasicAnimation* animation= [CABasicAnimationWithKeyPath:@"value"];
animation.duration=5;
animation.repeatCount=1;
animation.fromValue = [NSNumber numberWithFloat:0.0];
animation.toValue = [NSNumber numberWithFloat:per];
animation.fillMode=kCAFillModeForwards;
animation.removedOnCompletion=YES;
animation.timingFunction= [CAMediaTimingFunctionFunctionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[_graph addAnimation:animation forKey:@"key"; input
AnimatableGraph.h
@property(nonatomic)UIColor*fillColor;
AnimatableGraph.m
@implementationSKCircleGraphLayer{
CGFloat red, green, blue, alpha;
}
-(void)drawInContext:(CGContextRef)ctx{
fillColor getRed:&red green:&green blue:&blue alpha:&alpha];
NSLog(@"%f", red); // 0 during animation and 1 after completion.
CGContextSaveGState (ctx);
CGFloat x = self.bounds.origin.x;
x+ = self.bounds.size.width/2;
CGFloaty=self.bounds.origin.y;
y+=self.bounds.size.height/2;
CGContextSetLineWidth (ctx, 0);
CGMutablePathRef path=CGPathCreateMutable();
CGPathAddArc (path, NULL, x, y, x-10, 0, M_PI*2, NO);
CGContextAddPath(ctx, path);
CGContextSetRGBFillColor (ctx, 0.6, 0.6, 0.6, 1.0); // gray
CGContextSetLineWidth (ctx, 0);
CGContextDrawPath(ctx,kCGPathFillStroke);
// Correction as 3 o'clock direction is 0 degrees
double start=-45;
double aDegre=_degre-(180-start);
CGMutablePathRefgraph=CGPathCreateMutable();
CGPathAddArc (graph, nil, x, y, x-10, (M_PI* 2.0*(start-180)/360), (M_PI* 2.0)*(aDegree/360.0), false);
CGPathAddLineToPoint (graph, nil, x, y);
CGContextAddPath(ctx, graph);
CGContextSetRGBFillColor (ctx, red, green, blue, alpha);
CGContextDrawPath(ctx,kCGPathFillStroke);
CGContextRestoreGState (ctx);
}
First of all, I made a "move" program.However, there is no guarantee that this is the program that the questioner is looking for.
Paste the UIView instance graphView into the ViewController and draw a pie chart on it.Drawing a pie chart is done in GraphLayer, a subclass of CALayer.
ViewController.h -----------
#import<UIKit/UIKit.h>
// No changes.
@ interface ViewController:UIViewController
@end
ViewController.m ---------
#import "ViewController.h"
#import "GraphLayer.h"
@ interface ViewController()
// Paste the graphView in the Storyboard.It is recommended that you make it square.
@property(weak, nonatomic)IBOutlet UIView*graphView;
// Instance of GraphLayer.
@property(nonatomic)GraphLayer*graphLayer;
@end
@implementation ViewController
- (void) viewDidLoad{
superviewDidLoad;
self.graphLayer=[[GraphLayer alloc] init];
self.graphLayer.frame = CGRectMake (0.0, 0.0, self.graphView.frame.size.width, self.graphView.frame.size.height);
// The initial value of the pie chart is 40 percent.
self.graphLayer.perCent=40.0;
// The initial color of the pie chart is red. Notice that color information is handled by HSB.
UIColor*redColor= [UIColorredColor];
CGFloat theHue;
[redColor getHue: & theHue saturation: NULL brightness: NULL alpha: NULL];
self.graphLayer.hue =theHue;
[self.graphView.layer addSublayer:self.graphLayer];
}
// The action method to start the animation.
- (IBAction) animate: (id) sender {
CABasicAnimation*graphAnimation=[CABasicAnimation alloc] init];
graphAnimation.keyPath=@"perCent";
graphAnimation.fromValue = [NSNumber numberWithFloat:40.0];
// It shall be 90% after change.
self.graphLayer.perCent=90.0;
graphAnimation.toValue = [NSNumber numberWithFloat: 90.0];
CABasicAnimation*colorAnimation=[CABasicAnimation alloc] init];
// Change to blue.
colorAnimation.keyPath=@"hue";
UIColor*redColor= [UIColorredColor];
CGFloat redHue;
[redColor getHue: & redHue saturation: NULL brightness: NULL alpha: NULL];
colorAnimation.fromValue = [NSNumber numberWithFloat:redHue];
UIColor*blueColor= [UIColor blueColor];
CGFloat theHue;
[blueColor getHue: & theHue saturation: NULL brightness: NULL alpha: NULL];
self.graphLayer.hue =theHue;
colorAnimation.toValue = [NSNumber numberWithFloat:theHue];
// Use the CAAnimationGroup class to perform multiple animations simultaneously.
CAAnimationGroup*group=[CAAnimationGroup alloc] init];
group.animations=@[graphAnimation, colorAnimation];
group.duration=1.0;
[self.graphLayer addAnimation:group forKey:@"Graph";
}
@end
GraphicLayer.h ---------
#import<UIKit/UIKit.h>
// Xcode 6 and iOS 8.x don't need to import the QuartzCore framework.
#import<QuartzCore/QuartzCore.h>
@ interface GraphLayer: CALayer
@property(assign)CGFloat perCent;
Only hue is used as a property, not as a whole color information.
@property(assign)CGFloathue;
@end
GraphicLayer.m ---------
#import "GraphLayer.h"
@implementationGraphLayer{
CGFloat angle;
CGFloat radius;
UIColor*fillColor;
}
- (id) init {
self=[super init];
if(self){
// The default value is appropriate.
angle = 50.0;
fillColor= [UIColor blackColor];
// It seems necessary for animation processing.
self.needsDisplayOnBoundsChange=YES;
self.contentsScale=[UISscreen mainScreen].scale;
}
return self;
}
// It seems necessary for animation processing.
- (id) initWithLayer: (id)layer{
self=[super initWithLayer:layer];
if(self){
self.needsDisplayOnBoundsChange=YES;
self.contentsScale=[UISscreen mainScreen].scale;
}
return self;
}
// Specifies the key corresponding to the keyPath for CABasicAnimation.
+ (BOOL) needsDisplayForKey: (NSString*)key {
if([key isEqualToString:@"perCent"){
return YES;
} else if([key isEqualToString:@"hue"){
return YES;
}
return [super needsDisplayForKey:key];
}
// Drawing process. You can use CGPath instead of CGContext~.
- (void)drawInContext: (CGContextRef)ctx{
if(self.frame.size.width>=self.frame.size.height){
radius =self.frame.size.height/2.0;
} else{
radius =self.frame.size.width/2.0;
}
CGContextMoveToPoint (ctx, radius, radius);
CGContextAddArc (ctx, radius, radius, radius, radius, M_PI/-2.0, angle-M_PI/2.0, 0);
CGContextClosePath(ctx);
CGContextSetFillColorWithColor (ctx, fillColor.CGColor);
CGContextFillPath(ctx);
}
// Accessor Methods
// Convert percentage to angle.
- (CGFloat)perCent{
return angle/M_PI*50.0;
}
- (void) setPerCent: (CGFloat) perCent {
angle = M_PI*perCent/50.0;
}
// Generated UIColor from hue.
- (CGFloat) hue {
CGFloat theHue;
[fillColor getHue: & theHue saturation: NULL brightness: NULL alpha: NULL];
return theHue;
}
- (void)setHue: (CGFloat)hue {
fillColor=[UIColor alloc] initWithHue: hue saturation: 1.0 brightness: 1.0 alpha: 1.0 ];
}
@end
The problem with programming is that if UIColor and CGColor are set to keyPath of CABasicAnimation, they won't animate it.The CALayer property borderColor is CGColorRef type and it animates, so I should be able to use keyPath as CGColorRef, but I stopped considering it because it got troublesome.
© 2024 OneMinuteCode. All rights reserved.