gpt4 book ai didi

ios - 使用 Cglayer 绘图进行撤消和重做

转载 作者:行者123 更新时间:2023-12-01 18:03:48 26 4
gpt4 key购买 nike

我正在使用绘图应用程序,我使用 CGlayers 进行绘图。触摸结束时,我从图层中获取图像并将其存储在数组中,我用它来撤消操作。

我的触摸结束功能

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

我的绘图 View 根据用户需求动态扩展,因此假设用户可以绘制一条drawView大小为200*200的线,然后将其扩展至200*300并再绘制一条线,然后将其扩展至200*300并绘制还有一行。

这是应用程序的图像

现在我在 UndoArray 中有 3 个不同大小的图像。

每当我增加/减少 Canvas 大小时。我写了这段代码

关于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];
}

我没有什么疑问

  1. 这是正确的方法吗?或者他们有更好的方法吗?

  2. 这里发生的情况是,我的撤消数组中的图像不尊重矩形,而是在新图层上的任意随机位置绘制。

所以我想知道如何正确绘制它们,以便在 CGlayer 上的特定位置正确绘制图像。

最佳答案

首先,由于您正在使用图层,我建议放弃 drawRect: 并仅使用 CALayer 变换。

其次,在我看来,实现撤消重做操作的最佳方式始终是基于命令的。作为一个非常简单的示例,您可以为每个命令创建单独的方法:

- (void)scaleLayerBy:(CGFloat)scale;
- (void)moveLayerByX:(CGFloat)x Y:(CGFloat)y;
// etc

然后每次用户执行操作时,您都将操作 ID 和参数添加到 NSMutableArray 中:

[self.actionHistory addObject:@{ @"action": @"move", @"args": @[@10.0f, @20.0f] }];

相反,如果用户调用撤消,则删除该数组中的最后一个对象。

然后,当您需要重新加载显示时,只需重新评估数组中的所有命令即可。

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

关于ios - 使用 Cglayer 绘图进行撤消和重做,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21027788/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com