Struggling with issue since many days. Hope i can get an answer here. i have used this link to smoothen my free hand drawing. In this code i was able to set line width and color but i am finding it much difficult when i try to include undo/redo feauture in it using this link which is working fine on undo redo but its free hand dreawing is not smooth.
After some research and coding i am to know that its the cathing of drawing which is i think preventing the undo/redo.
In the first link there is a file "CachedLIView.h/m" when i used this and try to include undo/redo in this, i found that in the following method:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event // (2)
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[path addLineToPoint:p];
[self drawBitmap]; // (3)
[self setNeedsDisplay];
[path removeAllPoints]; //(4)
}
this method is calling drawBitMap: method which is actually generating a temporary image every time user lifts his finger and simultaneously removing points from 'path'.
- (void)drawBitmap // (3)
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0.0);
[[UIColor blackColor] setStroke];
if (!incrementalImage) // first draw; paint background white by ...
{
UIBezierPath *rectpath = [UIBezierPath bezierPathWithRect:self.bounds]; // enclosing bitmap by a rectangle defined by another UIBezierPath object
[[UIColor greenColor] setFill];
[rectpath fill]; // filling it with white
}
[incrementalImage drawAtPoint:CGPointZero];
//[path stroke];
for (UIBezierPath *_path in pathArray)
[_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
incrementalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
i am saving every path in an array so that i can do undo/redo. (took this idea from second link).
below is the complete code of this file that i have modified to include undo/redo:
#import "CachedLIView.h"
@implementation CachedLIView
{
UIBezierPath *path;
UIImage *incrementalImage; // (1)
}
- (id)initWithFrame:(CGRect)frame // (1)
{
if (self = [super initWithFrame:frame])
{
[self setMultipleTouchEnabled:NO]; // (2)
// [self setBackgroundColor:[UIColor whiteColor]];
// path = [[UIBezierPath alloc] init];
// [path setLineWidth:3];
pathArray=[[NSMutableArray alloc]init];
bufferArray=[[NSMutableArray alloc]init];
[self drawBitmap];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
NSLog(@"in drawrect pathArray[count]: %d", pathArray.count);
[incrementalImage drawInRect:rect]; // (3)
//[[UIColor blackColor] setStroke];
//[path stroke];
for (UIBezierPath *_path in pathArray)
[_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
path = [[UIBezierPath alloc] init];
path.lineWidth = 3;
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[path moveToPoint:p];
[pathArray addObject:path];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[path addLineToPoint:p];
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event // (2)
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[path addLineToPoint:p];
[self drawBitmap]; // (3)
[self setNeedsDisplay];
[path removeAllPoints]; //(4)
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
}
- (void)drawBitmap // (3)
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0.0);
[[UIColor blackColor] setStroke];
if (!incrementalImage) // first draw; paint background white by ...
{
UIBezierPath *rectpath = [UIBezierPath bezierPathWithRect:self.bounds]; // enclosing bitmap by a rectangle defined by another UIBezierPath object
[[UIColor greenColor] setFill];
[rectpath fill]; // filling it with white
}
[incrementalImage drawAtPoint:CGPointZero];
//[path stroke];
for (UIBezierPath *_path in pathArray)
[_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
incrementalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
#pragma mark - undo/redo
-(void)undoButtonClicked
{
if([pathArray count]>0){
UIBezierPath *_path=[pathArray lastObject];
[bufferArray addObject:_path];
[pathArray removeLastObject];
[self drawBitmap];
[self setNeedsDisplay];
}
}
-(void)redoButtonClicked
{
if([bufferArray count]>0){
UIBezierPath *_path=[bufferArray lastObject];
[pathArray addObject:_path];
[bufferArray removeLastObject];
[self drawBitmap];
[self setNeedsDisplay];
}
}
@end
.h file is:
#import <UIKit/UIKit.h>
@interface CachedLIView : UIView
{
NSMutableArray *pathArray;
NSMutableArray *bufferArray;
UIBezierPath *myPath;
}
-(void)undoButtonClicked;
-(void)redoButtonClicked;
@end
Please help me. What i am doing wrong. pathArray count is working correct. but not able to show undo/redo effect on screen.