I am working with unod redo operations on CgLayer, I have tried some code, but not able to get it working, dont know , where I am getting wrong, below is my code, which i have written
this is my drawRect function
- (void)drawRect:(CGRect)rect
{
m_backgroundImage = [UIImage imageNamed:@"bridge.jpg"];
CGPoint drawingTargetPoint = CGPointMake(0,0);
[m_backgroundImage drawAtPoint:drawingTargetPoint];
switch(drawStep)
{
case DRAW:
{
CGContextRef context = UIGraphicsGetCurrentContext();
if(myLayerRef == nil)
{
myLayerRef = CGLayerCreateWithContext(context, self.bounds.size, NULL);
}
CGContextDrawLayerAtPoint(context, CGPointZero, myLayerRef);
break;
}
case UNDO:
{
[curImage drawInRect:self.bounds];
break;
}
default:
break;
}
}
On touches ended , I am converting the layer into NSValue and storing as keyValue pair into NSDictionary and then adding the dictionary object to array.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSValue *layerCopy = [NSValue valueWithPointer:myLayerRef];
NSDictionary *lineInfo = [NSDictionary dictionaryWithObjectsAndKeys:layerCopy, @"IMAGE",
nil];
[m_pathArray addObject:lineInfo];
NSLog(@"%i",[m_pathArray count]);
}
below is my Undo functionality
- (void)undoButtonClicked
{
if([m_pathArray count]>0)
{
NSMutableArray *_line=[m_pathArray lastObject];
[m_bufferArray addObject:[_line copy]];
[m_pathArray removeLastObject];
drawStep = UNDO;
[self redrawLine];
}
}
//Redraw functions
- (void)redrawLine
{
NSDictionary *lineInfo = [m_pathArray lastObject];
NSValue *val = [lineInfo valueForKey:@"IMAGE"];
CGLayerRef layerToShow = (CGLayerRef) [val pointerValue];
CGContextRef context1 = CGLayerGetContext(layerToShow);
CGContextDrawLayerAtPoint(context1, CGPointMake(00, 00),layerToShow);
[self setNeedsDisplayInRect:self.bounds];
}
I think its here where I am goin wrong. So friends please help me out.
From the comments below, I have added the function, where its draws into Cglayer(this function I am calling into touchesMovedEvent.
- (void) drawingOperations
{
CGContextRef context1 = CGLayerGetContext(myLayerRef);
CGPoint mid1 = midPoint(m_previousPoint1, m_previousPoint2);
CGPoint mid2 = midPoint(m_currentPoint, m_previousPoint1);
CGContextMoveToPoint(context1, mid1.x, mid1.y);
CGContextAddQuadCurveToPoint(context1, m_previousPoint1.x, m_previousPoint1.y, mid2.x, mid2.y);
CGContextSetLineCap(context1, kCGLineCapRound);
CGContextSetLineWidth(context1, self.lineWidth);
CGContextSetStrokeColorWithColor(context1, self.lineColor.CGColor);
CGContextSetAllowsAntialiasing(context1, YES);
CGContextSetInterpolationQuality(context1, kCGInterpolationHigh);
CGContextSetAlpha(context1, self.lineAlpha);
CGContextStrokePath(context1);
}
Regards Ranjit
The best way to implement Undo and Redo is to implement NSUndoManager
as a brief description of it you don't have to save each state of Object that you want to undo or redo the NSUndoManager itself make this for you ...
Steps for reaching this is:
1- Initialize NSUndoManager.
2- Register Object state in the NSUndoManager object with specified function call will discuss this for you case later.
3-use undo or redo or clear actions function in NSUndoManager Object.
Ex from my working solution
-in .h file
@property (nonatomic,retain) NSUndoManager *undoManager;
in .m file
@synthesize undoManager;
in "viewDidLoad" method -- initialize your NSUndoManager
undoManager = [[NSUndoManager alloc] init];
Suppose that you have a function in your class that zoom in/out using pinch so in your "viewDidLoad" you will have
UIPinchGestureRecognizer *pinchGesture =
[[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinch:)];
pinchGesture.delegate = (id)self;
[self.view addGestureRecognizer:pinchGesture];
So pinch will zoom in/out such Note that "MyImageView" is the image that we want to zoom in/out
- (void)pinch:(UIPinchGestureRecognizer*)recognizer{
if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateChanged) {
NSLog(@"gesture.scale = %f", recognizer.scale);
CGFloat currentScale = self.MyImageView.frame.size.width / self.MyImageView.bounds.size.width;
CGFloat newScale = currentScale * recognizer.scale;
//Here is the line that register image to NSUndoManager before making and adjustments to the image "save current image before changing the transformation"
//Add image function is function that fired when you Make undo action using NSUndoManager "and so we maintain only image transformation that changed when you zoom in/out"
[[undoManager prepareWithInvocationTarget:self] AddImage:self.MyImageView.transform];
if (newScale < 0.5) {
newScale = 0.5;
}
if (newScale > 5) {
newScale = 5;
}
CGAffineTransform transform = CGAffineTransformMakeScale(newScale, newScale);
self.MyImageView.transform = transform;
recognizer.scale = 1;
}
}
-AddImage Function will save current image transformation state in NSUndoManager.
-(void)AddImage:(CGAffineTransform)sender{
CGAffineTransform transform = sender;
self.MyImageView.transform = transform;
}
So if you have button that make Undo action
-(IBAction)OptionsBtn:(id)sender{
if ([undoManager canUndo]) {
[undoManager undo];
}
}
So if you want to cancel all action you have both ways
while ([undoManager canUndo]) {
[undoManager undo];
}
OR
[undoManager removeAllActions];
(void)redrawLine { NSDictionary *lineInfo = [m_pathArray lastObject];
NSValue *val = [lineInfo valueForKey:@"IMAGE"];
CGContextRef context1 = (CGContextRef) [val pointerValue]; CGContextDrawLayerAtPoint(context1, CGPointMake(00, 00),layerToShow); [self setNeedsDisplayInRect:self.bounds]; }
just update this method with ur code
来源:https://stackoverflow.com/questions/11394839/undo-redo-issues-with-cglayer