问题
I was created UIView
with applying CAGradientLayer
color effect as i attached Image Bellow. Now in this i want to change it's gradient color change top to bottom side smoothly like screensaver. I have Been tried using NStimer
that bit Done but its changing color in CAGradientLayer
look like jerk.
For above I have use Bellow method of Code:-
Timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(TIMER) userInfo:nil repeats:NO];
-(void)TIMER
{
Count++;
[view_Color1 removeFromSuperview];
view_Color1 = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 341)];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = self.view_Color.bounds;
if (Count == 1)
{
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor greenColor] CGColor], (id)[[UIColor colorWithRed:44/255.0 green:255/255.0 blue:255/255.0 alpha:1.0f] CGColor], (id)[[UIColor colorWithRed:0/255.0 green:0/255.0 blue:254/255.0 alpha:1.0f] CGColor], (id)[[UIColor colorWithRed:252/255.0 green:0/255.0 blue:255/255.0 alpha:1.0f] CGColor], (id)[[UIColor colorWithRed:252/255.0 green:0/255.0 blue:6/255.0 alpha:1.0f] CGColor], (id)[[UIColor colorWithRed:253/255.0 green:131/255.0 blue:6/255.0 alpha:1.0f]CGColor], (id)[[UIColor colorWithRed:255/255.0 green:237/255.0 blue:10/255.0 alpha:1.0f]CGColor], nil];
}
else if (Count == 2)
{
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithRed:255/255.0 green:237/255.0 blue:10/255.0 alpha:1.0f]CGColor],(id)[[UIColor greenColor] CGColor], (id)[[UIColor colorWithRed:44/255.0 green:255/255.0 blue:255/255.0 alpha:1.0f] CGColor], (id)[[UIColor colorWithRed:0/255.0 green:0/255.0 blue:254/255.0 alpha:1.0f] CGColor], (id)[[UIColor colorWithRed:252/255.0 green:0/255.0 blue:255/255.0 alpha:1.0f] CGColor], (id)[[UIColor colorWithRed:252/255.0 green:0/255.0 blue:6/255.0 alpha:1.0f] CGColor], (id)[[UIColor colorWithRed:253/255.0 green:131/255.0 blue:6/255.0 alpha:1.0f]CGColor],nil];
}
//and so on still count is 7 then again its 1 to continue here are count use for chagen 7 color gradient use and repeat.
[self.view addSubview:view_Color1];
[self.view_Color1.layer addSublayer:gradient];
[myappdelegare sharedinstance].str_LastColorClick = [[NSString alloc]initWithFormat:@"MultiColor"];
Timer = [NSTimer scheduledTimerWithTimeInterval:0.30 target:self selector:@selector(TIMER) userInfo:nil repeats:NO];
}
Can you please help me?
Thanks
回答1:
I did not noticed first that you are "jumping" with colors at every step.
Here is a code which does the animation:
- (void) initGradient
{
if ( !gradient ) {
gradient = [CAGradientLayer layer];
gradient.frame = self.view.bounds;
[self.view.layer addSublayer:gradient];
NSArray *baseColors = [NSArray arrayWithObjects:(id)[UIColor yellowColor].CGColor, (id)[UIColor redColor].CGColor, (id)[UIColor blueColor].CGColor, (id)[UIColor greenColor].CGColor, nil];
NSMutableArray *colors = [NSMutableArray arrayWithArray:baseColors];
[colors addObjectsFromArray:baseColors];
gradient.colors = colors;
cnt = [baseColors count];
NSMutableArray *locations = [NSMutableArray array];
CGFloat step = 1. / (cnt - 1.);
CGFloat loc = 0;
for ( NSUInteger i = 0; i < [colors count]; i++ ) {
[locations addObject:@(loc)];
loc += step;
}
gradient.locations = [locations copy];
}
}
-(void)TIMER
{
NSMutableArray *locations = [NSMutableArray array];
CGFloat step = 1. / (cnt - 1.);
static const CGFloat speed = 3;
CGFloat initialStep = speed / gradient.bounds.size.height;
CGFloat loc = [gradient.locations[0] floatValue] - initialStep;
if ( loc <= -1 - step )
loc = initialStep;
for ( NSUInteger i = 0; i < [gradient.locations count]; i++ ) {
[locations addObject:@(loc)];
loc += step;
}
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
gradient.locations = [locations copy];
[CATransaction commit];
Count++;
if ( Count >= [gradient.colors count] )
Count = 0;
[self performSelector:@selector(TIMER) withObject:nil afterDelay:0.04];
}
It still has an small issue, that the top pixel of the view gets a mixed color but animates nicely. You can adjust the speed as well (static CGFloat speed). I leave it up to you to solve - maybe clip.
回答2:
If you want to animate layer properties do not use NSTimer, use one of the classes of CAAnimation
'family'. In your case if you want to animate between several different gradients then CAKeyFrameAnimation
is the right choice. Sample code to add layer animation to gradient layer:
- (void) addColorsAnimationToGradientLayer:(CAGradientLayer*)glayer {
NSMutableArray *colors = [glayer.colors mutableCopy];
NSMutableArray *animationColors = [@[] mutableCopy];
for (int i = 0; i < colors.count; ++i) {
[animationColors addObject:[colors copy]];
id lastColor = [colors lastObject];
[colors removeObjectAtIndex:colors.count-1];
[colors insertObject:lastColor atIndex:0];
}
CAKeyframeAnimation *kfAnimation = [CAKeyframeAnimation animationWithKeyPath:@"colors"];
kfAnimation.values = animationColors;
kfAnimation.duration = 5.0f;
kfAnimation.repeatCount = HUGE_VALF;
kfAnimation.autoreverses = YES;
[glayer addAnimation:kfAnimation forKey:@"colors"];
}
In the code listed above I create infinitely looping animation where gradient colors are obtained using cyclic permutation of colors in initial gradient:
KeyFrame0: [color0, color1, color2,…, colorN]
KeyFrame1: [colorN, color0, color1, color2,…, colorN-1]
…
KeyFrame(N-1): [color1, color2, color3,…, color0]
来源:https://stackoverflow.com/questions/20016213/how-to-change-color-of-cagradientlayer-like-screensaver