I am subclassing UIScrollView and adding some visual elements. At the top, there should be a gradient going from black to clear, and at the bottom there is a mask that fades out towards the bottom. I have those layers added and looking right, but when I scroll, they stay at the coordinates I put them in (with respect to the scroll view), rather than being "fixed" to the bottom and top of the view. This scroll view only scrolls vertically.
Here is the code for SettingsScrollView.m:
#import "SettingsScrollView.h"
#import <QuartzCore/QuartzCore.h>
#define SHADOW_HEIGHT 20.0
#define SHADOW_INVERSE_HEIGHT 10.0
#define SHADOW_RATIO (SHADOW_INVERSE_HEIGHT / SHADOW_HEIGHT)
@implementation SettingsScrollView
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
[self setUpShadow];
return self;
}
- (CAGradientLayer *)shadowAsInverse:(BOOL)inverse
{
CAGradientLayer *newShadow = [[[CAGradientLayer alloc] init] autorelease];
CGRect newShadowFrame = CGRectMake(0, 0, self.frame.size.width, inverse ? SHADOW_INVERSE_HEIGHT : SHADOW_HEIGHT);
newShadow.frame = newShadowFrame;
CGColorRef darkColor =[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:inverse ? (SHADOW_INVERSE_HEIGHT / SHADOW_HEIGHT) * 0.5 : 0.5].CGColor;
CGColorRef lightColor = [self.backgroundColor colorWithAlphaComponent:0.0].CGColor;
newShadow.colors = [NSArray arrayWithObjects: (id)(inverse ? lightColor : darkColor), (id)(inverse ? darkColor : lightColor), nil];
return newShadow;
}
- (CAGradientLayer *)gradientMask
{
CAGradientLayer *mask = [[[CAGradientLayer alloc] init] autorelease];
CGRect maskFrame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
mask.frame = maskFrame;
CGColorRef darkColor =[UIColor clearColor].CGColor;
CGColorRef lightColor =[UIColor blackColor].CGColor;
mask.colors = [NSArray arrayWithObjects: (id)lightColor, (id)lightColor, (id)darkColor, nil];
mask.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:0.9], [NSNumber numberWithFloat:1.0], nil];
return mask;
}
- (void)setUpShadow
{
CAGradientLayer *topShadowLayer = [self shadowAsInverse:NO];
CAGradientLayer *bottomShadowLayer = [self gradientMask];
[self.layer insertSublayer:topShadowLayer atIndex:0];
[self.layer setMask:bottomShadowLayer];
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
CGRect topShadowLayerFrame = topShadowLayer.frame;
topShadowLayerFrame.size.width = self.frame.size.width;
topShadowLayerFrame.origin.y = 0;
topShadowLayer.frame = topShadowLayerFrame;
CGRect bottomShadowLayerFrame = bottomShadowLayer.frame;
bottomShadowLayerFrame.size.width = self.frame.size.width;
bottomShadowLayerFrame.origin.y = self.frame.size.height - bottomShadowLayer.frame.size.height;
bottomShadowLayer.frame = bottomShadowLayerFrame;
[CATransaction commit];
}
@end
I know one solution for the top could just be to add a separate view that contains a gradient, but for the bottom I believe I need to use a mask to have it do what I want it to (fade out into the background at the very bottom). The background is an image so I can't just fade to white or another color, it needs to fade to clear. I've been looking for a method that gets called when the scroll view is moved and use that to change the position of the mask, but I haven't found anything yet. Any suggestions?