2014-01-29 63 views
2

我在图纸上的应用程序施工图,我想要做的撤销/重做,为此我对触摸节省CGPath端到NSMutableArray的,但我不理解我应该怎么上呈现CGPaths点击撤销按钮,撤销/重做用于iOS的

EDIT1:

由于我使用BezierPaths,于是,我第一次决定一起去的只是抚摸着这条路,没有CGPath一个简单的方法,

EDIT2:由于我的撤销是发生在细分(我,部分而不是整个路径被删除),我决定创建一个数组的数组,所以我做了相应的改变,现在我将绘制CGlay呃,带着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)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)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)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)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 lineSegmentPerpendicularTo:(LineSegment){pointsBuffer[i], pointsBuffer[i+1]} ofRelativeLength:frac1]; // ................. (5) 
         ls[2] = [self lineSegmentPerpendicularTo:(LineSegment){pointsBuffer[i+1], pointsBuffer[i+2]} ofRelativeLength:frac2]; 
         ls[3] = [self lineSegmentPerpendicularTo:(LineSegment){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)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
{  
    [parentUndoArray addObject:m_undoArray]; 

} 

我的drawRect方法是低于

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

- (void)drawRect:(CGRect)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]; 
} 

编辑2:现在,我现在面临的问题是,即使我绘制小路径或大路径,阵列数组中的数据是相同的。但是INFACT,小路径应该含有较少drawingPath对象和大的路径应包含在undoArray更drawingPath对象,它在最后被添加到阵列的阵列称为“ParentUndoArray

下面是屏幕截图,

1。一气描线的第一截屏无需提起手指

enter image description here

2,做撤消操作一次,只有线的段被去除之后

enter image description here

回答

2

我已经找到了一个解决方案,我们需要创建的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的路径。

+0

如何在这个链接中实现撤消功能回答..http:// stackoverflow .com/questions/23997525/how-to-draw-calayer-with-line-path-like-simulate-eraser-effect请帮助我.. –

1

如果您的drawRect方法可以得出任何CGPaths在数组中,所有你需要做的是通过调用setNeedsDisplay触发图纸再次撤消方法您已经删除最后添加CGPath

+0

Hello Niraj,如果你仔细看看我的代码,你会注意到,我在touchesMoved中完成了可变宽度,在这里我只是从UIBezeirPath中取出CgPath并绘制它。 – Ranjit

+0

可能,我没有很好地理解这个问题,但似乎你需要在任何给定的时间点重绘NSMutableArray中的路径。如果是这样的话,你应该将绘图代码从touchesMoved移动到一个单独的方法 – Niraj

1

我想以后你制作的路径对象比你想要的要多。我建议转到您的Alloc的bezierPath在触摸移动并更换

self.currentPath = [[DrawingPath alloc] init]; 

随着

if(!self.currentPath){ 
        self.currentPath = [[DrawingPath alloc] init]; 
} 
+0

我试过了,会发生什么情况是,如果我画两条线,然后如果我按撤消,那么第二行不会去,我有两次点击撤消3-4次,然后第二行消失,类似地,对于第一行 – Ranjit

+0

撤消代码在哪里交配?不要担心,我们可以做到这一点:) – Jef

+0

我会发布它,给我两分钟 – Ranjit

0

那么你应该这样做,因为它很容易

- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) { 
    // Initialization code 

    self.backgroundColor = [UIColor clearColor]; 
    myPath = [[UIBezierPath alloc] init]; 
    myPath.lineCapStyle = kCGLineCapRound; 
    myPath.miterLimit = 0; 
    bSize=5; 
    myPath.lineWidth = bSize; 
    brushPattern = [UIColor whiteColor]; 

    // Arrays for saving undo-redo steps in arrays 
    pathArray = [[NSMutableArray alloc] init]; 
    bufferArray = [[NSMutableArray alloc] init]; 


    } 
return self; 
} 

// Only override drawRect: if you perform custom drawing. 

// An empty implementation adversely affects performance during animation. 

- (void)drawRect:(CGRect)rect 
{ 
    [brushPattern setStroke]; 
    for (id path in pathArray){ 
     if ([path isKindOfClass:[UIBezierPath class]]) { 
      UIBezierPath *_path=(UIBezierPath *)path; 
      [_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0]; 
     } 
    } 
} 

#pragma mark - Touch Methods 
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 

     UITouch *mytouch = [[touches allObjects] objectAtIndex:0]; 
     myPath = [[UIBezierPath alloc] init]; 
     myPath.lineWidth = bSize; 
     [myPath moveToPoint:[mytouch locationInView:self]]; 
     [pathArray addObject:myPath]; 

} 

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    [myPath addLineToPoint:[[touches anyObject] locationInView:self]]; 
    [self setNeedsDisplay]; 
} 


#pragma mark - Undo Method 
-(void)undoButtonClicked 
{ 
    if([pathArray count]>0) 
    { 
     if ([[pathArray lastObject] isKindOfClass:[SPUserResizableView class]]) 
     { 
      [[pathArray lastObject] removeFromSuperview]; 
     } 
    UIBezierPath *_path = [pathArray lastObject]; 
    [bufferArray addObject:_path]; 
    [pathArray removeLastObject]; 
    [self setNeedsDisplay]; 
    } 

} 
-(void)setBrushSize: (CGFloat)brushSize 
{ 
    bSize=brushSize; 
} 

-(void)redoButtonClicked 
{ 
    if([bufferArray count]>0){ 
    UIBezierPath *_path = [bufferArray lastObject]; 
    [pathArray addObject:_path]; 
    [bufferArray removeLastObject]; 
    [self setNeedsDisplay]; 
    } 
} 
-(void)undoAllButtonClicked 
{ 
    [pathArray removeAllObjects]; 
    [self setNeedsDisplay]; 
} 

希望这将有助于。