Undo repeated issues with CGLayer

I work with unod redo operations on CgLayer, I tried some code, but could not get it to work, I don’t know where I am wrong, below is my code that I wrote

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; } } 

In the end, I convert the layer to NSValue and save it as keyValue to NSDictionary, and then add the dictionary object to the 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 Cancel function

 - (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 here where I am mistaken. So friends, please help me.

From the comments below, I added a function where it draws in Cglayer (I call this function in touchhesMovedEvent.

 - (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); } 

Ranjit Relations

+1
ios cocoa-touch quartz-graphics quartz-2d
Jul 09 '12 at 12:16
source share
2 answers

The best way to implement Undo and Redo is to implement NSUndoManager as a short description, you do not need to save every state of the object that you want to cancel or repeat, NSUndoManager will do it for you ..

Steps to achieve this:

1- Initialize NSUndoManager.

2- Register the state of the object in the NSUndoManager object with the specified function call will discuss this for you later.

3-use the undo or redo or clear function in the NSUndoManager object.

Ex from my working solution

-in.h file

 @property (nonatomic,retain) NSUndoManager *undoManager; 
  • in .m file

    @synthesize undoManager;

  • in viewDidLoad method - initialize NSUndoManager

    undoManager = [[NSUndoManager alloc] init];

Suppose you have a function in your class that zooms in / out with a 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 the pinch will zoom in / out Note that "MyImageView" is the image 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 the current state of image conversion to NSUndoManager.

 -(void)AddImage:(CGAffineTransform)sender{ CGAffineTransform transform = sender; self.MyImageView.transform = transform; } 

So, if you have a button that does the Undo action

 -(IBAction)OptionsBtn:(id)sender{ if ([undoManager canUndo]) { [undoManager undo]; } } 

So, if you want to undo all the actions, you have both ways.

 while ([undoManager canUndo]) { [undoManager undo]; } 

OR

 [undoManager removeAllActions]; 
+1
Jul 18 '12 at 12:35
source share
  • (voids) 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

0
Aug 23 2018-12-12T00:
source share



All Articles