How to erase finger paint on Custom UIView in iPhone

I have created a custom UIView (without .xib) for a finger paint application.

Paint is working fine with custom UIView but my problem is that when I try to erase the painted path I am getting:

  • rotate image using CGContextDrawImage
  • Drawing a dashed line with CGContextSetLineDash
  • Create new UIImage by adding shadow to existing UIImage
  • iOS draw filled Circles
  • Create a UIImage by rendering UIWebView on a background thread - iPhone
  • Calculate controlPoints while drawing in iOS
  • Error : Invalid context

    Below is my class:

    .h file

    @interface draw2D : UIView
    {
        CGPoint previousPoint;
        CGPoint lastPoint;
        CGMutablePathRef path;
        UIButton *btnClose;
        UIButton *btnErase;
        BOOL IsErase;
    }
    - (IBAction)btnClose:(id)sender;
    - (IBAction)btnErase:(id)sender;
    @end
    
    
    @implementation draw2D
    - (void)awakeFromNib
    {
        path = CGPathCreateMutable();
    }
    - (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) 
        {
            btnClose = [UIButton buttonWithType:UIButtonTypeRoundedRect];
            [btnClose addTarget:self action:@selector(btnClose:)
             forControlEvents:UIControlEventTouchDown];
            [btnClose setTitle:@"close" forState:UIControlStateNormal];
            btnClose.frame = CGRectMake(10, 10, 100, 40.0);
    
            btnErase = [UIButton buttonWithType:UIButtonTypeRoundedRect];
            [btnErase addTarget:self action:@selector(btnErase:)
               forControlEvents:UIControlEventTouchDown];
            [btnErase setTitle:@"Erase" forState:UIControlStateNormal];
            btnErase.frame = CGRectMake(150, 10, 100, 40.0);
    
            [self addSubview:btnClose];
            [self addSubview:btnErase];
        }
        return self;
    }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
    {    
        UITouch *touch = [touches anyObject];
        NSLog(@"Touch Began :%d",[touch tapCount]);
    
        if ([touch tapCount] > 1) 
        {
            NSLog(@"::::: Paint Start :::::");
            path = CGPathCreateMutable();
            previousPoint = lastPoint;
            [self setNeedsDisplay];
        }
        self.backgroundColor = [UIColor clearColor];
    }
    
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
    {
        NSLog(@"::::: touchesMoved :::::");
        lastPoint = [[touches anyObject] locationInView:self];
        previousPoint = [[touches anyObject] previousLocationInView:self];
    
        if(IsErase)
        {
            NSLog(@"erase");
            UITouch *erasetouch = [touches anyObject];  
            CGPoint erasecurrentPoint = [erasetouch locationInView:self];
    
            CGContextRef erasecontext = UIGraphicsGetCurrentContext();
            CGContextSetLineCap(erasecontext, kCGLineCapRound);
            CGContextSetLineWidth(erasecontext,10);
            CGContextSetBlendMode(erasecontext, kCGBlendModeClear);
            CGContextSetStrokeColorWithColor(erasecontext, [[UIColor clearColor] CGColor]);
            CGContextBeginPath(erasecontext);
            CGContextMoveToPoint(erasecontext, lastPoint.x, lastPoint.y);
            CGContextAddLineToPoint(erasecontext, erasecurrentPoint.x, erasecurrentPoint.y);
            CGContextStrokePath(erasecontext);     
            CGContextFlush(erasecontext);
    
        }  
    
        [self setNeedsDisplay];
    }
    - (void)drawRect:(CGRect)rect
    {
        NSLog(@"::::: drawRect :::::");
    
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGPathMoveToPoint(path, NULL, previousPoint.x, previousPoint.y);
        CGPathAddLineToPoint(path, NULL, lastPoint.x, lastPoint.y);
        CGContextAddPath(context, path);
        CGContextSetLineWidth(context, 5);
        [[UIColor blueColor] setStroke];
        CGContextDrawPath(context, kCGPathFillStroke);
    }
    
    - (IBAction)btnClose:(id)sender
    {
        [self removeFromSuperview];
    }
    - (IBAction)btnErase:(id)sender
    {
        IsErase = YES;
    }    
    
    @end
    

    I have set erase button with functionality but not working.

    2 Solutions Collect From Internet About “How to erase finger paint on Custom UIView in iPhone”

    The problem you have is that you are not supposed to call UIGraphicGetContext() outside of drawRect:

    In your touchesBegan:withEvent: and touchesMoved:withEvent: you should simply store the points you want to draw and call [self setNeedsDisplay] as you are doing now.
    In your drawRect: implementation you would then draw the points you have stored.

    You can take a look at this github repo that provides an implementation for a smooth drawing:https://github.com/levinunnink/Smooth-Line-View

    finally i have find the solution . my mistake was i m implement erase code intouchMove method with new context . i dont have to need new context . implement erase code in drawrect method and now its working fine . see the below code.

    - (void)drawRect:(CGRect)rect
    {
    
        [curImage drawAtPoint:CGPointMake(0, 0)];
        CGPoint mid1 = midPoint(previousPoint1, previousPoint2); 
        CGPoint mid2 = midPoint(currentPoint, previousPoint1);
    
        context = UIGraphicsGetCurrentContext(); 
        [self.layer renderInContext:context];
    
        if(IsErase)
        {
            CGContextSetLineWidth(context,self.lineWidth);
            CGContextSetBlendMode(context, kCGBlendModeClear);
            CGContextSetStrokeColorWithColor(context, [[UIColor clearColor] CGColor]);
            CGContextBeginPath(context);
            CGContextMoveToPoint(context, mid1.x, mid1.y);
            CGContextAddLineToPoint(context, previousPoint1.x, previousPoint1.y);
            CGContextStrokePath(context);     
            CGContextFlush(context);
        }
        else
        {
            CGContextMoveToPoint(context, mid1.x, mid1.y);
            CGContextAddQuadCurveToPoint(context, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y); 
            CGContextSetLineCap(context, kCGLineCapRound);
            CGContextSetLineWidth(context, self.lineWidth);
            CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
            CGContextSaveGState(context);
            CGContextStrokePath(context);
        }
        [super drawRect:rect];
        [curImage release];
    }
    

    i hope it will helps to someone in erase functionality .