Cocoa and iOS Development

Archive for the ‘UIView’ tag

UIView Additions

leave a comment

The most valuable asset a working developer can have is a solid base of reusable code for common occurrences. This often takes the form of well-abstracted classes, but by using categories in Objective-C, you can make the standard Cocoa classes more powerful by adding your own methods. Every so often we’ll put up some of our favorite class additions, which when used together can form the basis of a personalized development framework to make your life easier.

Since the front-end staple of almost any iOS app is the view hierarchy, let’s start with UIView additions that can make your code cleaner and your app look sharper.

I tend to use a few staple methods that I cribbed from the inimitable Joe Hewitt’s original three20 library, particularly:

- (void)setOrigin:(CGPoint)inOrigin {
	[self setFrame:CGRectMake(inOrigin.x, inOrigin.y, self.frame.size.width, self.frame.size.height)];

- (void)setSize:(CGSize)inSize {
	[self setFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, inSize.width, inSize.height)];

- (void)removeAllSubviews {
	for (UIView *tmpView in [self subviews]) {
		[tmpView removeFromSuperview];

Though in general you want your view controllers smart and your views dumb, it’s occasionally useful to know what view controller’s hierarchy a given view is attached to. Your code should never rely on this sort of thing, but during debugging, I find this bad boy really helpful:

- (UIViewController *)viewController {
	for (UIView *next = [self superview]; next; next = next.superview) {
		UIResponder *nextResponder = [next nextResponder];
		if ([nextResponder isKindOfClass:[UIViewController class]]) {
			return (UIViewController *)nextResponder;
	return nil;

If you’re dynamically sizing your views or setting the center property, you have to be careful not to set your frames using half-pixels, or they’ll end up blurry. In general it’s better to calculate your frames cleanly, but I’m also a fan of this quick-and-dirty way of making sure you’re not straddling any lines:

- (void)align {
	[self setFrame:CGRectMake((int)self.frame.origin.x, 

Quartz ninja that she is, Sarah has come up with some tasty methods to jazz up your views. Be sure and link to QuartzCore and import <QuartzCore/QuartzCore.h> in the file where you define these methods.

- (void)addShadow {
    if (self.layer.shadowOpacity == 0 && self.width > 0) {
        self.layer.shadowColor = [[UIColor blackColor] CGColor];
        self.layer.shadowRadius = 10.0f;
        CGRect path = CGRectMake(10, self.height - 15, self.width -20, 25);
        self.layer.shadowPath = [[UIBezierPath bezierPathWithRect:path] CGPath];
        CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
        anim.fromValue = [NSNumber numberWithFloat:0.0];
        anim.toValue = [NSNumber numberWithFloat:1.0];
        anim.duration = .2;
        [self.layer addAnimation:anim forKey:@"shadowOpacity"];
        self.layer.shadowOpacity = 1.0;

- (void)removeShadow {
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
    anim.fromValue = [NSNumber numberWithFloat:1.0];
    anim.toValue = [NSNumber numberWithFloat:0.0];
    anim.duration = .2;
    [self.layer addAnimation:anim forKey:@"shadowOpacity"];
    self.layer.shadowOpacity = 0.0;

- (void)showBounce {
    self.alpha = 0;
    self.hidden = NO;
    [UIView animateWithDuration:0.1 animations:^{self.alpha = 1.0;}];
    self.layer.transform = CATransform3DMakeScale(0.5, 0.5, 1.0);
    CAKeyframeAnimation *bounceAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
    bounceAnimation.values = [NSArray arrayWithObjects:
                              [NSNumber numberWithFloat:0.5],
                              [NSNumber numberWithFloat:1.1],
                              [NSNumber numberWithFloat:0.8],
                              [NSNumber numberWithFloat:1.0], nil];
    bounceAnimation.duration = 0.3;
    bounceAnimation.removedOnCompletion = NO;
    [self.layer addAnimation:bounceAnimation forKey:@"bounce"];
    self.layer.transform = CATransform3DIdentity;

- (void)drawGradiant:(CGRect)rect colors:(NSArray *)inColors{
    CGFloat colors[[inColors count]*4]; 
    int i = 0;
    for (UIColor *item in inColors) {
        CGFloat newComponents[4] = {};
        memcpy(newComponents, CGColorGetComponents([item CGColor]), sizeof(newComponents));
        colors[i++] = newComponents[0];
        colors[i++] = newComponents[1];
        colors[i++] = newComponents[2];
        colors[i++] = newComponents[3];
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
    CGGradientRef gradient = CGGradientCreateWithColorComponents(rgb, colors, NULL, sizeof(colors)/(sizeof(colors[0])*4));
    CGContextClipToRect(context, rect);
    CGPoint start = CGPointMake(rect.origin.x, rect.origin.y);  
    CGPoint end = CGPointMake(rect.origin.x, rect.size.height); 
    CGContextDrawLinearGradient(context, gradient, start, end, kCGGradientDrawsBeforeStartLocation);

Written by Joe

January 24th, 2012 at 7:00 pm

Posted in Uncategorized

Tagged with , ,