2011年12月29日星期四

Using blocks for drawing to avoid subclassing in Objective-C

Using blocks for drawing to avoid subclassing in Objective-C

It is very common for a designer to ask for a 1 pixel tall bar here, or a small gradient there. This is a small request that isn’t very hard, right? Subclass UIView, override drawRect and do the drawing using Core Graphics. But every time you do this you need to add a file to your project. And all this file does is include 1 drawRect method with likely very little code. It personally bothers me when I see lot’s of these little classes that don’t do very much.

Block Based Solution

Instead of subclassing UIView every time we need to draw something what if we were to have one subclass that allowed us to pass in a block that performed the drawing code. So I’ve created a class called DrawView that does exactly that. It also passes itself and the graphics context since that was going to be needed in every block’s implementation so including them as parameters reduced the amount of boiler plate code needed.
typedef void(^DrawView_DrawBlock)(UIView* v,CGContextRef context);
@interface DrawView : UIView
@property (nonatomic,copy) DrawableView_DrawBlock drawBlock;
@end
#import "DrawView.h"
@implementation DrawView
@synthesize drawBlock;
- (void)dealloc
{
    [drawBlock release], drawBlock = nil;
    [super dealloc];
}
- (void)drawRect:(CGRect)rect
{
    [super drawRect:rect];
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    if(self.drawBlock)
        self.drawBlock(self,context);
}
@end
Using this class in action is easy. Simply instantiate a DrawView object and pass in a drawBlock with some Core Graphics code in there.
DrawView* drawableView = [[[DrawView alloc] initWithFrame:CGRectMake(0,0,320,50)] autorelease];
drawableView.drawBlock = ^(UIView* v,CGContextRef context)
{
    CGPoint startPoint = CGPointMake(0,v.bounds.size.height-1);
    CGPoint endPoint = CGPointMake(v.bounds.size.width,v.bounds.size.height-1);
    CGContextSetStrokeColorWithColor(context, [UIColor grayColor].CGColor);
    CGContextSetLineWidth(context, 1);
    CGContextMoveToPoint(context, startPoint.x + 0.5, startPoint.y + 0.5);
    CGContextAddLineToPoint(context, endPoint.x + 0.5, endPoint.y + 0.5);
    CGContextStrokePath(context);
};
[self.view addSubview:drawableView];

About.

Hi, I'm David Hamrick. I'm currently working as an iOS developer at Mercury in Nashville, TN. I'm also the author of VueScan Mobile, an easy to use app that allows you to scan from HP, Canon, and Epson printer/scanners to your iPhone, iPad, and iPod Touch.

没有评论:

发表评论