• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

ios - 在 iOS 中撤消/重做绘图

[复制链接]
菜鸟教程小白 发表于 2022-12-13 06:13:34 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题

我正在开发一个绘图应用程序,我想做撤消/重做,为此我将触摸结束时的 CGPath 保存到 NSMutableArray,但我不明白如何在单击撤消按钮时呈现 CGPaths

编辑1:

由于我使用的是 BezierPaths,所以,我首先决定采用一种简单的方法,即在不使用 CGPath 的情况下抚摸这条路径,

EDIT2:由于我的撤消是在分段中进行的(即,部分而不是整个路径被删除),我决定创建一个数组数组,所以我进行了相应的更改,现在我将在 CGlayer 中绘制,用CGPath

所以这里的“parentUndoArray”是数组数组。

所以我就这样做了

我有一个名为 DrawingPath 的类来进行绘图

//DrawingPath.h

@interface DrawingPath : NSObject

@property (strong, nonatomic) NSString    *pathWidth;
@property (strong,nonatomic) UIColor      *pathColor;
@property (strong,nonatomic) UIBezierPath *path;

- (void)draw;

@end

//DrawingPath.m

#import "DrawingPath.h"

@implementation DrawingPath


@synthesize pathWidth = _pathWidth;
@synthesize pathColor = _pathColor;
@synthesize path = _path;


- (id)init {

    if (!(self = [super init] ))
        return nil;



    _path = [[UIBezierPath alloc] init];
    _path.lineCapStyle=kCGLineCapRound;
    _path.lineJoinStyle=kCGLineJoinRound;

    [_path setLineWidth:2.0f];

    return self;
}

- (void)draw
{

    [self.pathColor setStroke];
    [self.path stroke];

}

所以现在在我的 DrawingView 中,我是这样做的

-(void)touchesBeganNSSet *)touches withEventUIEvent *)event
{
     ctr = 0;
    bufIdx = 0;
    UITouch *touch = [touches anyObject];
    pts[0] = [touch locationInView:self];
    isFirstTouchPoint = YES;

    [m_undoArray removeAllObjects];//On every touches began clear undoArray

}

-(void)touchesMovedNSSet *)touches withEventUIEvent *)event
{
            UITouch *touch = [touches anyObject];

            CGPoint p = [touch locationInView:self];
            ctr++;
            pts[ctr] = p;


            if (ctr == 4)
            {
                pts[3] = midPoint(pts[2], pts[4]);


                for ( int i = 0; i < 4; i++)
                {
                    pointsBuffer[bufIdx + i] = pts[i];
                }

                bufIdx += 4;

                dispatch_async(drawingQueue, ^{


                    self.currentPath = [[DrawingPath alloc] init];
                    [self.currentPath setPathColor:self.lineColor];

                    if (bufIdx == 0) return;

                    LineSegment ls[4];
                    for ( int i = 0; i < bufIdx; i += 4)
                    {
                        if (isFirstTouchPoint) // ................. (3)
                        {

                            ls[0] = (LineSegment){pointsBuffer[0], pointsBuffer[0]};
                            [self.currentPath.path moveToPoint:ls[0].firstPoint];


                           // [offsetPath addLineToPoint:ls[0].firstPoint];
                            isFirstTouchPoint = NO;

                        }
                        else
                        {
                            ls[0] = lastSegmentOfPrev;

                        }


                        float frac1 = self.lineWidth/clamp(len_sq(pointsBuffer[i], pointsBuffer[i+1]), LOWER, UPPER); // ................. (4)
                        float frac2 = self.lineWidth/clamp(len_sq(pointsBuffer[i+1], pointsBuffer[i+2]), LOWER, UPPER);
                        float frac3 = self.lineWidth/clamp(len_sq(pointsBuffer[i+2], pointsBuffer[i+3]), LOWER, UPPER);


                        ls[1] = [self lineSegmentPerpendicularToLineSegment){pointsBuffer[i], pointsBuffer[i+1]} ofRelativeLength:frac1]; // ................. (5)
                        ls[2] = [self lineSegmentPerpendicularToLineSegment){pointsBuffer[i+1], pointsBuffer[i+2]} ofRelativeLength:frac2];
                        ls[3] = [self lineSegmentPerpendicularToLineSegment){pointsBuffer[i+2], pointsBuffer[i+3]} ofRelativeLength:frac3];


                        [self.currentPath.path  moveToPoint:ls[0].firstPoint]; // ................. (6)
                        [self.currentPath.path  addCurveToPoint:ls[3].firstPoint controlPoint1:ls[1].firstPoint controlPoint2:ls[2].firstPoint];
                        [self.currentPath.path  addLineToPoint:ls[3].secondPoint];
                        [self.currentPath.path  addCurveToPoint:ls[0].secondPoint controlPoint1:ls[2].secondPoint controlPoint2:ls[1].secondPoint];
                        [self.currentPath.path  closePath];

                        lastSegmentOfPrev = ls[3]; // ................. (7)
                    }     


                    [m_undoArray addObject:self.currentPath];

                     EDIT:2 
                    CGPathRef cgPath = self.currentPath.path.CGPath;
                    mutablePath = CGPathCreateMutableCopy(cgPath);


                    dispatch_async(dispatch_get_main_queue(), ^{
                    bufIdx = 0;
                    [self setNeedsDisplay];

                        });
                    });


                pts[0] = pts[3];
                pts[1] = pts[4]; 
                ctr = 1;
            }
        }
    }
}

-(void)touchesEndedNSSet *)touches withEventUIEvent *)event
{       
     [parentUndoArray addObject:m_undoArray];

}

下面是我的drawRect方法

编辑:现在我的 DrawRect 有两种情况

  - (void)drawRectCGRect)rect
{    
    switch (m_drawStep)
   {
       case DRAW:
       {

           CGContextRef context = UIGraphicsGetCurrentContext();//Get a reference to current context(The context to draw)



           CGContextRef layerContext = CGLayerGetContext(self.currentDrawingLayer);
           CGContextBeginPath(layerContext);
           CGContextAddPath(layerContext, mutablePath);
           CGContextSetStrokeColorWithColor(layerContext, self.lineColor.CGColor);
           CGContextSetFillColorWithColor(layerContext, self.lineColor.CGColor);
           CGContextSetBlendMode(layerContext,kCGBlendModeNormal);
           CGContextDrawPath(layerContext, kCGPathFillStroke);
          // CGPathRelease(mutablePath);



          CGContextDrawLayerInRect(context,rectSize, self.newDrawingLayer);
          CGContextDrawLayerInRect(context, self.bounds, self.permanentDrawingLayer);
          CGContextDrawLayerInRect(context, self.bounds, self.currentDrawingLayer );

          }
           break;




       case UNDO:
       {           
           for(int i = 0; i<[m_parentUndoArray count];i++)
           {
               NSMutableArray *undoArray = [m_parentUndoArray objectAtIndex:i];

               for(int i =0; i<[undoArray count];i++)
               {
                   DrawingPath *drawPath = [undoArray objectAtIndex:i];
                   [drawPath draw];
               }
           }


       }
           break;


       [super drawRect:rect];
}

EDIT2:现在我面临的问题是,即使我绘制小路径或大路径,数组数组中的数据都是相同的。但实际上,小路径应该包含较少的drawingPath对象,大路径应该包含更多的undoArray中的drawingPath对象,最后添加到名为“ParentUndoArray”的数组数组中

这是屏幕截图,

1.第一屏不抬手指,一气呵成的画线截图

enter image description here

2、执行一次undo操作后,只删除该行的一部分

enter image description here



Best Answer-推荐答案


我已经找到了解决方案,我们需要创建一个 DrawingPaths 的数组:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
   // Do the above code, then
   [m_undoArray addObject:self.currentPath];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
   [m_parentUndoArray addObject:[NSArray arrayWithArray:m_undoArray]];
}

然后在DrawRect中描边路径。

关于ios - 在 iOS 中撤消/重做绘图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21438586/

回复

使用道具 举报

懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关注0

粉丝2

帖子830918

发布主题
阅读排行 更多
广告位

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap