Skip to content

Commit 89f3e39

Browse files
Implement gradient backgrounds for views
1 parent 6ebeec7 commit 89f3e39

5 files changed

Lines changed: 118 additions & 5 deletions

File tree

Classes/ViewStyling/GAViewStyling.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,22 @@
5050

5151
@end
5252

53+
#pragma mark -
54+
5355
/**
5456
* Returns a size from a CSS declaration that contains two lengths (i.e. "320px 240px").
5557
* The first length is width (x), the second is height (y). If the string does not have at least two lengths,
5658
* the function returns CGSizeZero.
5759
*/
5860
CGSize GASizeFromCSSLengths (NSString* cssString);
61+
62+
#pragma mark -
63+
64+
@interface CAGradientLayer (GAViewStyling)
65+
66+
/**
67+
* Support setting a gradient from the WebKit gradient CSS declaration.
68+
*/
69+
- (void)setValuesWithCSSGradient:(NSString *)cssGradient;
70+
71+
@end

Classes/ViewStyling/GAViewStyling.m

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,37 @@ CGSize GASizeFromCSSLengths (NSString* cssString)
151151
return CGSizeMake(x, y);
152152
}
153153

154+
#pragma mark -
155+
156+
@implementation CAGradientLayer (GAViewStyling)
157+
158+
/**
159+
* Creates a gradient layer using the CSS specification from WebKit.
160+
*
161+
* Example: -webkit-gradient(linear, 0% 100%, 0% 0%,
162+
* color-stop(0.19, rgb(128, 22, 48)), color-stop(0.6, rgb(224, 36, 74)), color-stop(0.8, rgb(235, 52, 88)))
163+
*/
164+
- (void)setValuesWithCSSGradient:(NSString *)cssGradient
165+
{
166+
if ([cssGradient length] == 0 || ![cssGradient hasPrefix:@"-webkit-gradient(linear,"])
167+
return;
168+
169+
NSArray* colorStops = [cssGradient componentsSeparatedByString:@", color-stop("];
170+
NSMutableArray* colors = [[NSMutableArray alloc] initWithCapacity:[colorStops count]];
171+
NSMutableArray* locations = [[NSMutableArray alloc] initWithCapacity:[colorStops count]];
172+
173+
for (NSInteger i = 1; i < [colorStops count]; ++i)
174+
{
175+
NSString* colorStop = [colorStops objectAtIndex:i];
176+
[locations addObject:[NSNumber numberWithFloat:[colorStop floatValue]]];
177+
[colors addObject:(id)[UIColor colorWithCSSColor:colorStop].CGColor];
178+
}
179+
180+
[self setColors:colors];
181+
[self setLocations:locations];
182+
[colors release];
183+
[locations release];
184+
}
185+
186+
@end
187+

Classes/ViewStyling/UIView+GAViewStyling.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,10 @@
7979

8080
@end
8181

82+
@interface UITableViewCell (GAViewStyling)
83+
84+
- (void)applyComputedStyles:(id)cssDeclaration;
85+
86+
@end
87+
88+

Classes/ViewStyling/UIView+GAViewStyling.m

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ - (NSString *)styleSelector
4848
- (void)applyStylesWithScriptEngine:(GAScriptEngine *)engine
4949
{
5050
NSString* selector = [self styleSelector];
51+
#if 1
5152
NSLog(@"GAViewStyling selector: %@", selector);
53+
#endif
5254

5355
id element = [[engine documentObject] querySelector:selector];
5456

@@ -73,13 +75,26 @@ - (void)applyComputedStyles:(id)cssDeclaration
7375

7476
NSString* backgroundImage = [cssDeclaration valueForKey:@"background-image"];
7577

76-
// TODO: If this view's layer is a CAGradientLayer, we can use a webkit linear gradient
78+
// If this view's layer is a CAGradientLayer, we can use a webkit linear gradient
7779
// -webkit-gradient(<type>, <point>, <point> [, <stop>]*)
7880
//
79-
if ([backgroundImage hasPrefix:@"-webkit-gradient(linear,"]
80-
&& [self.layer isKindOfClass:[CAGradientLayer class]])
81+
if ([backgroundImage hasPrefix:@"-webkit-gradient(linear,"])
8182
{
82-
NSLog(@"TODO: Gradient: %@", backgroundImage);
83+
CAGradientLayer* gradLayer = [self.layer.sublayers objectAtIndex:0];
84+
85+
if (![gradLayer valueForKey:@"GAViewStylingID"])
86+
{
87+
gradLayer = [CAGradientLayer layer];
88+
[gradLayer setValue:@"-webkit-gradient" forKey:@"GAViewStylingID"];
89+
90+
CGRect bounds = [self bounds];
91+
[gradLayer setBounds:bounds];
92+
[gradLayer setPosition:CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds))];
93+
94+
[self.layer insertSublayer:gradLayer atIndex:0];
95+
}
96+
97+
[gradLayer setValuesWithCSSGradient:backgroundImage];
8398
}
8499

85100
NSString* opacity = [cssDeclaration valueForKey:@"opacity"];
@@ -180,7 +195,7 @@ - (void)applyComputedStyles:(id)cssDeclaration
180195
@implementation UITableView (GAViewStyling)
181196

182197
- (void)applyComputedStyles:(id)cssDeclaration
183-
{
198+
{
184199
[super applyComputedStyles:cssDeclaration];
185200

186201
// Border (Separator) Color. We use "top" because it's the first color in TRBL.
@@ -202,3 +217,14 @@ - (void)applyComputedStyles:(id)cssDeclaration
202217

203218
@end
204219

220+
@implementation UITableViewCell (GAViewStyling)
221+
222+
- (void)applyComputedStyles:(id)cssDeclaration
223+
{
224+
if (self.backgroundView) // Don't apply background styles to this view
225+
return;
226+
227+
[super applyComputedStyles:cssDeclaration];
228+
}
229+
230+
@end

Tests/TViewStyling.m

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2727
*/
2828

2929
#import "TViewStyling.h"
30+
#import <QuartzCore/QuartzCore.h>
3031
#import "GAViewStyling.h"
3132

3233
@implementation TViewStyling
@@ -138,6 +139,38 @@ - (void)testSizeFromCSSLengths
138139
GHAssertTrue(size.width == 0 && size.height == 0, @"Bad string not handled!");
139140
}
140141

142+
- (void)testGradientLayer
143+
{
144+
CAGradientLayer* layer = [CAGradientLayer layer];
145+
146+
NSString* cssGradient = @"-webkit-gradient(linear, 100% 0%, 0% 100%, color-stop(0.19, rgb(128, 22, 48)), color-stop(0.6, rgb(224, 36, 74)), color-stop(0.8, rgb(235, 52, 88)))";
147+
[layer setValuesWithCSSGradient:cssGradient];
148+
149+
GHAssertNotNil(layer, @"Bad layer");
150+
GHAssertTrue([layer.colors count] == 3, @"Wrong number of colors");
151+
152+
CGColorRef color1 = (CGColorRef)[layer.colors objectAtIndex:0];
153+
const CGFloat* pColors = CGColorGetComponents(color1);
154+
GHAssertTrue(pColors[0] == 128/255.f && pColors[1] == 22/255.f && pColors[2] == 48/255.f, @"Bad colors");
155+
156+
CGColorRef color2 = (CGColorRef)[layer.colors objectAtIndex:1];
157+
pColors = CGColorGetComponents(color2);
158+
GHAssertTrue(pColors[0] == 224/255.f && pColors[1] == 36/255.f && pColors[2] == 74/255.f, @"Bad colors");
159+
160+
CGColorRef color3 = (CGColorRef)[layer.colors objectAtIndex:2];
161+
pColors = CGColorGetComponents(color3);
162+
GHAssertTrue(pColors[0] == 235/255.f && pColors[1] == 52/255.f && pColors[2] == 88/255.f, @"Bad colors");
163+
164+
NSNumber* loc1 = [layer.locations objectAtIndex:0];
165+
GHAssertTrue([loc1 floatValue] == 0.19f, @"Location wrong");
166+
167+
NSNumber* loc2 = [layer.locations objectAtIndex:1];
168+
GHAssertTrue([loc2 floatValue] == 0.6f, @"Location wrong");
169+
170+
NSNumber* loc3 = [layer.locations objectAtIndex:2];
171+
GHAssertTrue([loc3 floatValue] == 0.8f, @"Location wrong");
172+
}
173+
141174
@end
142175

143176
#pragma mark -

0 commit comments

Comments
 (0)