Search code examples
iosobjective-cbackgroundcalayer

CALayer background color


I have a CALayer background using:

CAGradientLayer *bgLayer = [BackgroundLayer blueGradient];
bgLayer.frame = self.view.bounds;
[self.view.layer insertSublayer:bgLayer atIndex:0];

In

- (void)prepareToRotate:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration

I use this line to rotate the CALayer background.

[[[self.view.layer sublayers] objectAtIndex:0] setFrame:self.view.bounds];

I am getting some tearing effects that are not pretty as the layer seemingly doesn't rotate fast enough, how can I fix this and get a seamless effect on rotate, is there a better way to resize the calayer?

Thanks,

EDIT: All my code:

the .h:

#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>


@interface BackgroundLayer : NSObject

+(CAGradientLayer*) greyGradient;
+(CAGradientLayer*) blueGradient;

@end

the .m

#import "BackgroundLayer.h"

@implementation BackgroundLayer

//Metallic grey gradient background
+ (CAGradientLayer*) greyGradient {

UIColor *colorOne       = [UIColor colorWithWhite:0.9 alpha:1.0];
UIColor *colorTwo       = [UIColor colorWithHue:0.625 saturation:0.0 brightness:0.85 alpha:1.0];
UIColor *colorThree     = [UIColor colorWithHue:0.625 saturation:0.0 brightness:0.7 alpha:1.0];
UIColor *colorFour      = [UIColor colorWithHue:0.625 saturation:0.0 brightness:0.4 alpha:1.0];

NSArray *colors =  [NSArray arrayWithObjects:(id)colorOne.CGColor, colorTwo.CGColor, colorThree.CGColor, colorFour.CGColor, nil];

NSNumber *stopOne       = [NSNumber numberWithFloat:0.0];
NSNumber *stopTwo       = [NSNumber numberWithFloat:0.02];
NSNumber *stopThree     = [NSNumber numberWithFloat:0.99];
NSNumber *stopFour      = [NSNumber numberWithFloat:1.0];

NSArray *locations = [NSArray arrayWithObjects:stopOne, stopTwo, stopThree, stopFour, nil];

CAGradientLayer *headerLayer = [CAGradientLayer layer];
headerLayer.colors = colors;
headerLayer.locations = locations;

return headerLayer;
}

//Blue gradient background
+ (CAGradientLayer*) blueGradient {
  UIColor *colorOne = [UIColor colorWithRed:(120/255.0) green:(135/255.0) blue:(150/255.0)   alpha:1.0];
  UIColor *colorTwo = [UIColor colorWithRed:(57/255.0)  green:(79/255.0)  blue:(96/255.0)  alpha:1.0];

NSArray *colors = [NSArray arrayWithObjects:(id)colorOne.CGColor, colorTwo.CGColor, nil];

NSNumber *stopOne = [NSNumber numberWithFloat:0.0];
NSNumber *stopTwo = [NSNumber numberWithFloat:1.0];

NSArray *locations = [NSArray arrayWithObjects:stopOne, stopTwo, nil];

CAGradientLayer *headerLayer = [CAGradientLayer layer];
headerLayer.colors = colors;
headerLayer.locations = locations;

return headerLayer;

}

@end

Prepare to rotate is simply called by

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    [self prepareToRotate:[[UIApplication sharedApplication] statusBarOrientation] duration:0];

}

and just contains

[[[self.view.layer sublayers] objectAtIndex:0] setFrame:self.view.bounds];


Solution

  • I'd recommend to use CAGradientLayer over CoreGraphics. It is much faster to render. For your issue, try to rasterize your view before the rotation.

    - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
    {
        self.bgLayer.shouldRasterize = YES;
    }
    

    Actually, you can add a subview instead of a new layer.

    @interface MyView : UIView
    
    @end
    
    @implementation MyView
    
    + (Class)layerClass
    {
        return [CAGradientLayer class];
    }
    
    @end
    

    In your old inserting layer part, do following instead.

    MyView *bgView = [[MyView alloc] initWithFrame:self.view.bounds];
    [(CAGradientLayer *)bgView.layer setColors:colors];
    bgView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    
    [self.view insertSubview:bgView atIndex:0];
    

    (You can use auto-layout if you want)