21

I'm trying to create a UIView subclass ("GradientView") that will fill itself with a gradient of various colors. I've implemented it by adding a CAGradientLayer as a sub-layer of UIView's layer.

It looked good, but when the screen was rotated, it didn't resize the gradient layer. Having no luck finding a BOOL property on the layer to toggle, I overrode layoutSubviews in the GradientView.

-(void)layoutSubviews {
    self.gradientLayer.frame = self.bounds;
}

This works, but the stuff behind the GradientView is still visible during the device rotation animation. What is the easiest way to 'autoresize' that CAGradientLayer to match its parent layer's bounds so that the animation is smooth (like for UIView autoresizing)?

Moduspwnens
  • 525
  • 1
  • 5
  • 9

5 Answers5

29

You can probably get away with defining the +layerClass method on a custom UIView...

@implementation MyGradientView
+(Class) layerClass {
    return [CAGradientLayer class];
}
@end

You can initialize the layer in your controller's viewDidLoad() (or wherever), something like...

-(void)viewDidLoad {
    [super viewDidLoad];
    [(CAGradientLayer*)[mMyGradientViewInstance layer] setColors:nil];
}
l8nite
  • 5,042
  • 1
  • 20
  • 23
  • 2
    +1 Works nicely. The layer size is managed by the parent UIView and resized automatically. – Adolfo Feb 15 '11 at 08:35
  • 7
    This answer is not very clear. I have tried many hours but not worked – DavidNg Aug 14 '12 at 00:24
  • Works great! Anyone wanting to use this on grouped UITableViewCells, don't forget that you need to subclass a normal UIView and set is as the backgroundView of the cell (instead of subclassing the cell itself). – SpacyRicochet Feb 03 '13 at 22:05
  • 2
    I think the missing piece of information here is that by subclassing this method, you make the layer you create the main 'layer' for the view. Since it's the view's main layer, the framework will take care of autoresizing it for you as necessary. – Shaun Budhram Feb 06 '14 at 08:22
4

I would:

  1. Increase the size of your view to the maximum of each dimension in the willRotateToInterfaceOrientation code. (For example for an 320x480 iPhone - set the dims to 480x480).

  2. Set the bounds in accordance to the newly-rotated view in the didRotateFromInterfaceOrientation function.

This should make it so that the view is large enough so that regardless of how it is oriented during animation, it will cover the entire screen. It won't be "smooth" - because the gradient will have to be rotated, but at least you will not see behind the layer in the middle of the rotation.

Brad
  • 11,262
  • 8
  • 55
  • 74
  • 1
    Okay - got a better idea? I use this tequnique in mapping programs, where I have to rotate from a 320x480 to a 480x320 and want it to appear seamless. – Brad Oct 19 '10 at 16:29
  • Please see criteria for downvoting: http://stackoverflow.com/privileges/vote-down – Brad Oct 19 '10 at 19:23
  • lesson learned, brad can you edit you answer,(even if its just capitalising a word) and i will take the dv off. (vote is locked unless edit) – Luke Mcneice Oct 20 '10 at 08:08
  • This is a bit of a hack, but as you can clip the view to it's bounds it works – Magoo Feb 02 '15 at 14:24
2
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

    CGRect b;

    if(UIInterfaceOrientationIsLandscape(toInterfaceOrientation))b = CGRectMake(0, 0, 480, 320);
    else b = CGRectMake(0, 0, 320, 480);    

    [CATransaction begin];
    [CATransaction setValue:[NSNumber numberWithFloat:duration] forKey:kCATransactionAnimationDuration];
    [self.view.layer setBounds:b];
    [CATransaction commit];

}
Luke Mcneice
  • 3,012
  • 4
  • 38
  • 50
  • Why do you think we explicitly have to change the bounds of the layer? Layer should be automatically resized when associated view's frame is changed, isnt it? – Raj Pawan Gumdal Jan 17 '12 at 10:38
1

Note that returning CAGradientLayer as the layer class only works if you set the view background color to transparent. You'll need to set the layer background color if you need a color other than transparent.

user1172004
  • 177
  • 2
  • 4
0

in my case this work:

[[[view.layer sublayers] objectAtIndex:gradientIndex] setFrame:view.bounds];
Onnmir
  • 1,030
  • 14
  • 17
  • I add your code in `(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration`. When I rotate, the old layer is still exit. The new layer in landscape mode still appear. Please help me – DavidNg Aug 14 '12 at 00:27