Here’s a neat little tip I’ve found can spruce up your applications easily. It’s very easy to create a UIView with a solid background colour, but in our new rainbow coloured Web 2.0 shiny iPhone world, gradients are called for. You could of course create a gradient image and set the background image of the view, but this has several drawbacks:
- For every different sized view, you either need to re-cut the gradient image or scale it.
- It is a waste of space in your application, plus gradient images are often quite big files.
- You need an image for each colour.
- It is relatively expensive to load and render an image as a background for a view.
However using a bit of trickery, you can create a general GradientView class which extends UIView and overrides drawRect to achieve a gradient background. So I present GradientView:
//
// GradientView.m
// evilrockhopper
//
// Created by Daniel Wichett on 10/12/2009.
//
// Extension of UIView to show a gradient, generally used as a background on other views.
// Mirrored indicates a gradient that is colour1 -> colour2 -> colour1. Non-mirrored simply goes from colour1 -> colour2.
#import "GradientView.h"
@implementation GradientView
@synthesize mirrored;
- (void)drawRect:(CGRect)rect
{
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGGradientRef glossGradient;
CGColorSpaceRef rgbColorspace;
size_t numLocations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
//Two colour components, the start and end colour both set to opaque.
CGFloat components[8] = { startRed, startGreen, startBlue, 1.0, endRed, endGreen, endBlue, 1.0 };
rgbColorspace = CGColorSpaceCreateDeviceRGB();
glossGradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, numLocations);
CGRect currentBounds = self.bounds;
CGPoint topCenter = CGPointMake(CGRectGetMidX(currentBounds), 0.0f);
CGPoint midCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMaxY(currentBounds)/2.0);
CGPoint bottomCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMaxY(currentBounds));
if (!mirrored)
{
// draw a gradient from top to bottom centred.
CGContextDrawLinearGradient(currentContext, glossGradient, topCenter, bottomCenter, 0);
}
else
{
// draw a gradient from top to middle, then reverse the colours and draw from middle to bottom.
CGContextDrawLinearGradient(currentContext, glossGradient, topCenter, midCenter, 0);
CGFloat components2[8] = { endRed, endGreen, endBlue, 1.0, startRed, startGreen, startBlue, 1.0 };
CGGradientRelease(glossGradient);
glossGradient = CGGradientCreateWithColorComponents(rgbColorspace, components2, locations, num_locations);
CGContextDrawLinearGradient(currentContext, glossGradient, midCenter, bottomCenter, 0);
}
// Release our CG objects.
CGGradientRelease(glossGradient);
CGColorSpaceRelease(rgbColorspace);
}
// Set colours as component RGB.
- (void) setColours:(float) _startRed:(float) _startGreen:(float) _startBlue:(float) _endRed:(float) _endGreen:(float)_endBlue
{
startRed = _startRed;
startGreen = _startGreen;
startBlue = _startBlue;
endRed = _endRed;
endGreen = _endGreen;
endBlue = _endBlue;
}
// Set colours as CGColorRefs.
- (void) setColoursWithCGColors:(CGColorRef)color1:(CGColorRef)color2
{
const CGFloat *startComponents = CGColorGetComponents(color1);
const CGFloat *endComponents = CGColorGetComponents(color2);
[self setColours:startComponents[0]:startComponents[1]:startComponents[2]:endComponents[0]:endComponents[1]:endComponents[2]];
}
- (void)dealloc
{
[super dealloc];
}
@end
And the header file GradientView.h as so:
//
// GradientView.h
// evilrockhopper
//
// Created by Daniel Wichett on 10/12/2009.
//
#import <UIKit/UIKit.h>
@interface GradientView : UIView
{
float startRed;
float startGreen;
float startBlue;
float endRed;
float endGreen;
float endBlue;
BOOL mirrored;
}
@property (nonatomic) BOOL mirrored;
- (void) setColoursWithCGColors:(CGColorRef)color1:(CGColorRef)color2;
- (void) setColours:(float) startRed:(float) startGreen:(float) startBlue:(float) endRed:(float) endGreen:(float)endBlue;
@end
So an example usage could be:
GradientView *redToBlack = [[GradientView alloc] initWithFrame:CGRectMake(0,0,320,50)];
[gradientBg setColoursWithCGColors:[UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0].CGColor:[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0].CGColor];
This creates a vertical gradient from red to black. If you wanted it to go from red to black to red, you can just set redToBlack.mirrored = YES.
It currently ignores the alpha value of the colours passed in, this would be trivial to add of course if required. If you want to experiment with other types of gradients, read the documentation for CGGradientCreateWithColorComponents. Feel free to use the code above, you can download the source by clicking on the menu in the top right of each code snippet.
Comment spammers scum, Wordpress and re-CAPTCHA
The spam comments on this site were progressively getting worse and worse. It’s a ridiculous situation since all comments are only show after approval so not a single one was ever being shown on the site. But it still takes time to monitor and becomes more annoying as time goes on. This morning I had already had 10 and so decided enough is enough.
I installed the very excellent re-CAPTCHA. This captcha software is a bit different for several reasons. Firstly it has a Wordpress plugin which took 5s to install. Secondly it helps organisations digitise books, a very honourable motive. To install you just need to:
So how does re-CAPTCHA work then? Captchas rely on testing if you are human by quizzing you on something that should be easy for a human and relatively hard for a computer to solve. OCR, i.e. recognising the image of a word as text can be extremely hard for computers if the page is distorted, grainy or badly printed. So re-CAPTCHA asks you to OCR two words. Why two? Well one is already known since it has been confirmed by other users (how else would re-CAPTCHA know your answer was correct), the other is not known and so you are providing a useful service helping a document be recognised (and providing new captcha answers for other users). Simple but ingenius.