我正在使用绘图应用程序,正在使用CGlayers进行绘图。触摸结束时,我将图像从图层中取出并存储在Array中,以用于撤消操作。
我的触摸结束功能
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"Touches ended"); UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextDrawLayerInRect(context, self.bounds, self.drawingLayer); m_curImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); [m_undoArray addObject: m_curImage]; }
我的绘图视图根据用户需求动态扩展,因此假设用户可以绘制一条具有drawView尺寸200 * 200的线,然后将其扩展到200 * 300并再画一条线,然后将其扩展到200 * 300并再画一条线。
这是应用程序的图像
所以现在我在UndoArray中有3张不同大小的图像。
每当我增加/减小画布大小时。我已经写了这段代码
在增加和减少drawingView时,我正在编写此函数
(void)increaseDecreaseDrawingView { self.currentDrawingLayer = nil; if(self.permanentDrawingLayer) { rectSize = self.bounds; NSLog(@"Size%@", NSStringFromCGRect(self.bounds)); CGContextRef context = UIGraphicsGetCurrentContext(); //self.newDrawingLayer = CGLayerCreateWithContext(context, self.bounds.size, NULL); CGFloat scale = self.contentScaleFactor; CGRect bounds = CGRectMake(0, 0, self.bounds.size.width * scale, self.bounds.size.height * scale); CGLayerRef layer = CGLayerCreateWithContext(context, bounds.size, NULL); CGContextRef layerContext = CGLayerGetContext(layer); CGContextScaleCTM(layerContext, scale, scale); self.newDrawingLayer = layer; CGContextDrawLayerInRect(layerContext, self.bounds, self.permanentDrawingLayer ); self.permanentDrawingLayer = nil; }
对于撤消,我已经编写了这段代码
- (void)Undo { //Destroy the layer and create it once again with the image you get from undoArray. self.currentDrawingLayer = Nil; CGContextRef layerContext1 = CGLayerGetContext(self.permanentDrawingLayer ); CGContextClearRect(layerContext1, self.bounds); CGContextRef context = UIGraphicsGetCurrentContext(); for(int i =0; i<[m_rectArrayUndo count];i++) { CGRect rect = [[m_rectArrayUndo objectAtIndex:i]CGRectValue]; CGLayerRef undoLayer = CGLayerCreateWithContext(context, rect.size, NULL); CGContextRef layerContext = CGLayerGetContext(undoLayer ); CGContextTranslateCTM(layerContext, 0.0, rect.size.height); CGContextScaleCTM(layerContext, 1.0, -1.0); CGRect imageFrame; NSDictionary *lineInfo = [m_undoArray objectAtIndex:i]; m_curImage = [lineInfo valueForKey:@"IMAGE"]; imageFrame = CGRectMake(0 ,0,m_curImage.size.width,m_curImage.size.height); CGContextDrawImage(layerContext, imageFrame, m_curImage.CGImage); CGContextDrawLayerInRect(context, rect, undoLayer ); CGContextDrawLayerInRect(layerContext1, rect, undoLayer); } }
在我的drawRect函数中,我编写了这段代码
- (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext();//Get a reference to current context(The context to draw) if(self.currentDrawingLayer == nil) { CGLayerRef layer = CGLayerCreateWithContext(context, bounds.size, NULL); self.currentDrawingLayer = layer; } if(self.permanentDrawingLayer == nil) { CGLayerRef layer = CGLayerCreateWithContext(context, bounds.size, NULL); self.permanentDrawingLayer = layer; } if(self.newDrawingLayer == nil) { CGLayerRef layer = CGLayerCreateWithContext(context, bounds.size, NULL); self.newDrawingLayer = layer; } CGPoint mid1 = midPoint(m_previousPoint1, m_previousPoint2); CGPoint mid2 = midPoint(m_currentPoint, m_previousPoint1); CGContextRef layerContext = CGLayerGetContext(self.currentDrawingLayer); CGContextSetLineCap(layerContext, kCGLineCapRound); CGContextSetBlendMode(layerContext, kCGBlendModeNormal); CGContextSetLineJoin(layerContext, kCGLineJoinRound); CGContextSetLineWidth(layerContext, self.lineWidth); CGContextSetStrokeColorWithColor(layerContext, self.lineColor.CGColor); CGContextSetShouldAntialias(layerContext, YES); CGContextSetAllowsAntialiasing(layerContext, YES); CGContextSetAlpha(layerContext, self.lineAlpha); CGContextSetFlatness(layerContext, 1.0f); CGContextBeginPath(layerContext); CGContextMoveToPoint(layerContext, mid1.x, mid1.y);//Position the current point CGContextAddQuadCurveToPoint(layerContext, m_previousPoint1.x, m_previousPoint1.y, mid2.x, mid2.y); CGContextStrokePath(layerContext);//paints(fills) the line along the current path. CGContextDrawLayerInRect(context, self.bounds, self.newDrawingLayer); CGContextDrawLayerInRect(context, self.bounds, self.permanentDrawingLayer); CGContextDrawLayerInRect(context, self.bounds, self.currentDrawingLayer); [super drawRect:rect]; }
我毫不怀疑
这是正确的方法吗?还是他们有更好的方法。
在这里发生的是,我从undo数组获得的图像不符合rect的要求,而是在新图层上的任意随机位置绘制的。
因此,我想知道如何正确绘制它们,以便在特定位置的CGlayer上正确绘制图像。
首先,由于您正在使用图层,因此我建议放弃drawRect:
并仅使用CALayer
转换。
其次,我认为,实现撤消重做操作的最佳方法始终是基于命令的。作为一个非常简单的示例,您可以为每个命令创建单独的方法:
- (void)scaleLayerBy:(CGFloat)scale; - (void)moveLayerByX:(CGFloat)x Y:(CGFloat)y; // etc
然后,用户每次执行操作时,您都将添加一个NSMutableArray
操作ID和参数:
[self.actionHistory addObject:@{ @"action": @"move", @"args": @[@10.0f, @20.0f] }];
相反,如果用户调用undo,则删除该数组中的最后一个对象。
然后,当您需要重新加载显示时,只需重新评估阵列中的所有命令即可。
[self resetLayers]; // reset CALayers to their initial state for (NSDictionary *command in self.actionHistory) { NSArray *arguments = command[@"args"]; if ([command[@"action"] isEqualToString:@"move"]) { [self moveLayerByX:[arguments[0] floatValue] Y:[arguments[1] floatValue]]; } // else if other commands }