如何像屏幕保护程序一样更改 CAGradientLayer 的颜色?

Posted

技术标签:

【中文标题】如何像屏幕保护程序一样更改 CAGradientLayer 的颜色?【英文标题】:How to change color of CAGradientLayer like screensaver? 【发布时间】:2013-11-16 08:02:53 【问题描述】:

我被创建UIView 应用CAGradientLayer 颜色效果作为我附加的图像波纹管。现在在这个我想改变它的渐变颜色从上到下平滑地改变,就像屏幕保护程序一样。我已经尝试使用 NStimer 那位 Done 但它在 CAGradientLayer 中的变化颜色看起来像混蛋。

对于上面我使用了 Bellow 的代码方法:-

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


你能帮帮我吗?

谢谢

【问题讨论】:

不流畅,因为您每秒只渲染 10/3 帧。将时间间隔更改为 0.04 (25 fps)。 它在 0.04 中也出现了抖动。感谢您的帮助 【参考方案1】:

我一开始没有注意到你每一步都在“跳跃”。

这里是一个做动画的代码:

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

它还有一个小问题,即视图的顶部像素得到了混合颜色,但动画效果很好。您也可以调整速度(静态 CGFloat 速度)。我把它留给你解决 - 也许是剪辑。

【讨论】:

嗨@Szabi Tolnai,你的作品非常好,效果很好。但它是从下到上的。你能再帮忙做一件事吗?它是如何从上到下的 嗨@Szabi Tolnai 你能告诉我怎么从上到下做吗?非常感谢 @BhaveshLakum 尝试从 -1 和 TIMER 设置初始位置,而不是 += 使用 -= 并相应地调整限制和 if ( loc 嗨@SzabiTolnai 通过这样做它不是从上到下动画你能给出正确的解决方案吗?谢谢【参考方案2】:

如果要为图层属性设置动画,请不要使用 NSTimer,请使用 CAAnimation 'family' 的类之一。在您的情况下,如果您想在几个不同的渐变之间制作动画,那么CAKeyFrameAnimation 是正确的选择。将图层动画添加到渐变图层的示例代码:

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

在上面列出的代码中,我创建了无限循环动画,其中渐变颜色是使用初始渐变中颜色的循环排列获得的:

KeyFrame0: [color0, color1, color2,…, colorN]
KeyFrame1: [colorN, color0, color1, color2,…, colorN-1]
…
KeyFrame(N-1): [color1, color2, color3,…, color0]

【讨论】:

以上是关于如何像屏幕保护程序一样更改 CAGradientLayer 的颜色?的主要内容,如果未能解决你的问题,请参考以下文章

如何像闹钟小部件(时钟应用程序)一样显示小部件?

如何在手表操作系统中设计像朋友应用一样的手表应用屏幕?

如何使用户控件像窗口一样在屏幕上可拖动

是否可以像在 android 中一样为我的应用程序的活动创建一个最近的屏幕

如何获得像屏幕捕获效果一样的屏幕闪光效果?

如何像 Skype 一样将 QDialog 粘贴到屏幕边框?