Problem: I had to develop a demo app for a lottery ticket. It had to have a scratch off part, where user will scratch off a top layer to see if he had won anything.
Description: No description for you 🙂 Problem is quite obvious.
Solution:
I’ve created a view (I’ve called it ScratchView) that has a UIImageView on it. UIImageView is stretched across the whole view, but if you wanna you can pick your own width and height. Background of my view is set to clear color and I’ve painted my UIImageView with black color. Here’s the code that does it:
- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.backgroundColor = [UIColor clearColor]; scratchField = [[UIImageView alloc] initWithFrame:self.bounds]; scratchField.backgroundColor = [UIColor clearColor]; [self addSubview:scratchField]; //overlay scratchField with black layer (rectagle) [scratchField.image drawInRect:scratchField.bounds]; CGSize size; size.height = scratchField.bounds.size.height; size.width = scratchField.bounds.size.width; UIGraphicsBeginImageContext(size); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetRGBFillColor(context, 0.96, 0.35, 0.0, 1.0); CGContextFillRect(context, scratchField.bounds); scratchField.image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); } return self; }
Just to point out, self, in this context is a view (ScratchView). It’s not a view controller, just a plain view.
Next thing I had to do is create a scratch of effect. It wasn’t that hard after I discovered one life saving line of code 🙂 But lets start from beginning. To create a scratch off effect i had to delete color (set color to clear) on my UIImageView. So what I did is I used touchesBegan and touchesMoved actions. On touchesBegan I just took start point of users touch. And in touchesMoved I’m erasing a line (or a curve if you wish) from users start point to current point. At the end I copy current point to users start point and if user continues to move just repeat the same method. Think that code is self explanatory but I wanna point out the money winning line of code. It’s this one:
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);
You can set blending mode to clear and what that does is exactly what I was looking for. It doesn’t paint on your UIImageView, it sets it to clear. So where ever you move your finger it will set that path to clear. Here’s the rest of the code.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; if ([touch tapCount] == 2) { //taped 2 time return; } userPoint = [touch locationInView:scratchField]; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; CGPoint currentPoint = [touch locationInView:scratchField]; UIGraphicsBeginImageContext(scratchField.frame.size); [scratchField.image drawInRect:scratchField.bounds]; CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear); CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound); //kCGLineCapSquare, kCGLineCapButt, kCGLineCapRound CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 25.0); // for size CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0); //values for R, G, B, and Alpha CGContextBeginPath(UIGraphicsGetCurrentContext()); CGContextMoveToPoint(UIGraphicsGetCurrentContext(), userPoint.x, userPoint.y); CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y); CGContextStrokePath(UIGraphicsGetCurrentContext()); scratchField.image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); userPoint = currentPoint; }
Hope this helps. You can find a full project here (btw: there is a view controller called ScratchTiceketViewController. Just ignore it. It was my test view controller and I’m to lazy to remove it :))
http://www.4shared.com/file/j1g6ieI5/TestingScratchTicketEffekt.html
All comments are welcomed. I publish all my blog notifications on my twitter so if you wanna you can follow me @ http://twitter.com/PavlovicMario