Reputation: 1040
I don't what's the right title for this but this is something like a scratch and reveal thing.
Here what it's like. I have to overlapping UIImageViews, now what I want to do is erase certain portion of the view where the touch point is to reveal the image behind. It is something like the drawing on touch but what it does is it'll erase certain points instead of drawing on it.
I tried searching on the web but I can't find anything.
Anyone has an idea?
Upvotes: 2
Views: 2502
Reputation: 437872
If you decide to roll your own, it's just a process of having two images, one with the scratch entirely revealed, the other with the scratch portion entirely hidden. You present these two images right on top of each other, updating and applying a mask to the front image based upon a gesture recognizer. (You can either completely mask away the front image at first and then unmask portions as the user scratches, or as I have here, completely show the front image and mask away portions away as the user scratches.) Anyway, as you update/apply masks to the front image, that will dictate how much of the rear image will show through.
I'm no Core Graphics guy, but it might look something like:
- (void)viewDidLoad
{
[super viewDidLoad];
UIImage *backgroundImage = [UIImage imageNamed:@"imgres-1.jpg"];
_foregroundImage = [UIImage imageNamed:@"imgres-2.jpg"];
CGRect frame = CGRectMake((self.view.frame.size.width - _foregroundImage.size.width) / 2.0,
(self.view.frame.size.height - _foregroundImage.size.height) / 2.0,
_foregroundImage.size.width,
_foregroundImage.size.height);
UIImageView *backgroundImageView = [[UIImageView alloc] initWithFrame:frame];
backgroundImageView.image = backgroundImage;
[self.view addSubview:backgroundImageView];
_foregroundImageMask = [self createBlankMaskForImage:_foregroundImage];
UIImageView *_foregroundImageView = [[UIImageView alloc] initWithFrame:frame];
_foregroundImageView.image = [self maskImage:_foregroundImage withMask:_foregroundImageMask]; // _foregroundImage;
[self.view addSubview:_foregroundImageView];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
_foregroundImageView.userInteractionEnabled = YES;
[_foregroundImageView addGestureRecognizer:pan];
}
- (void)pan:(UIPanGestureRecognizer *)sender
{
static CGPoint lastPoint;
UIImageView *maskedImageView = (UIImageView*)sender.view;
CGPoint location = [sender locationInView:maskedImageView];
if (sender.state == UIGestureRecognizerStateBegan)
{
lastPoint = location;
}
else if (sender.state == UIGestureRecognizerStateChanged)
{
UIGraphicsBeginImageContext(_foregroundImage.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[_foregroundImageMask drawInRect:maskedImageView.bounds];
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, 24.0);
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextBeginPath(context);
CGContextMoveToPoint(context, lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(context, location.x, location.y);
CGContextStrokePath(context);
_foregroundImageMask = UIGraphicsGetImageFromCurrentImageContext();
maskedImageView.image = [self maskImage:_foregroundImage withMask:_foregroundImageMask];
lastPoint = location;
}
}
- (UIImage *)createBlankMaskForImage:(UIImage *)image
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGContextRef context = CGBitmapContextCreate (NULL, image.size.width, image.size.height,
8, 0, colorSpace, kCGImageAlphaNone);
CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.0); // don't use alpha
CGContextFillRect(context, CGRectMake(0.0, 0.0, image.size.width, image.size.height));
CGImageRef imageref = CGBitmapContextCreateImage(context);
UIImage *result = [UIImage imageWithCGImage:imageref];
CGColorSpaceRelease(colorSpace);
CGContextRelease(context);
CFRelease(imageref);
return result;
}
// the following came from http://mobiledevelopertips.com/cocoa/how-to-mask-an-image.html
- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage
{
CGImageRef maskRef = maskImage.CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
CGImageGetHeight(maskRef),
CGImageGetBitsPerComponent(maskRef),
CGImageGetBitsPerPixel(maskRef),
CGImageGetBytesPerRow(maskRef),
CGImageGetDataProvider(maskRef), NULL, false);
CGImageRef masked = CGImageCreateWithMask([image CGImage], mask);
UIImage *result = [UIImage imageWithCGImage:masked];
CGImageRelease(masked);
CGImageRelease(mask);
return result;
}
Probably obvious, but this uses two ivars:
UIImage *_foregroundImage;
UIImage *_foregroundImageMask;
This isn't a terribly elegant implementation, but it gives you the basic idea. You can run with it as you see fit.
Upvotes: 1
Reputation: 11452
There is one awesome control on github, it's MIT Licensed. May be it will help you to get some idea,
https://github.com/akopanev/iOS-Scratch-n-See
Good luck!
Upvotes: 9