UIBezierPath undo drawing redraw UIImageView's image

妖精的绣舞 提交于 2019-12-08 02:54:05

问题


I'm trying to redraw my UIImageView's image by redrawing all UIBezierPaths and associated UIColors in an NSMutableArray I have created, minus the last path when I tap an undo UIButton.

However, the UIImageView's image doesn't redraw and remove the last path in this case, until the NSMutableArray's count is less than 2, in which it sets the UIImageView's image to nil (this is working correctly)

I'd appreciate any help offered. Note: I'm not including my touchesMoved method because I just want to get undoing 'dots' to work for now.

**

Update: here is the code I ended up using, with the help of the accepted answer below:

**

- (void)undoLast
{
    if (self.drawingPathArray.count < 2)
    {
        self.drawingPathArray = nil;
        self.undoButton.hidden = YES;
        self.drawingImageView.image = nil;
    }
    else
    {
        [self.drawingPathArray removeLastObject];

        self.undoButton.tintColor = [[self.drawingPathArray lastObject] objectAtIndex:0];

        UIGraphicsBeginImageContextWithOptions(self.drawingImageView.bounds.size, NO, 0.0);

        for (NSArray *subArray in self.drawingPathArray)
        {
            CGContextRef context = UIGraphicsGetCurrentContext();
            CGContextSetLineWidth(context, 3.0);
            CGContextSetLineCap(context, kCGLineCapRound);
            CGContextSetStrokeColorWithColor(context, [[subArray objectAtIndex:0] CGColor]);
            CGContextAddPath(context, [[subArray objectAtIndex:1] CGPath]);
            CGContextStrokePath(context);
        }

        self.drawingImageView.image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    }
}

Original question's code:

@property (nonatomic, strong) NSMutableArray *drawingPathArray;
@property (nonatomic, assign) NSInteger ctr;
@property (nonatomic, assign) CGPoint lastPoint;
CGPoint pts[4];

- (void)undoLast
{
    if (self.drawingPathArray.count < 2)
    {
        self.drawingPathArray = nil;
        self.undoButton.hidden = YES;
        self.drawingImageView.image = nil;
    }
    else
    {
        [self.drawingPathArray removeLastObject];

        NSArray *lastArray = [self.drawingPathArray lastObject];

        UIColor *lastColor = [lastArray objectAtIndex:0];

        self.undoButton.tintColor = lastColor;

        for (NSArray *subArray in self.drawingPathArray)
        {
            // These colors and paths are getting set correctly, verified by using NSLog
            UIColor *color = [subArray objectAtIndex:0];
            UIBezierPath *path = [subArray objectAtIndex:1];

            [self drawWithPath:path andColor:color];
        }
    }
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{           
    self.ctr = 0;
    UITouch *touch = [touches anyObject];
    pts[0] = [touch locationInView:self.drawingImageView];
}

- (void)drawWithPath:(UIBezierPath *)path andColor:(UIColor *)color
{
    path.lineWidth = 3.0;
    path.lineCapStyle = kCGLineJoinRound;

    dispatch_async(dispatch_get_main_queue(),
    ^{
        UIGraphicsBeginImageContextWithOptions(self.drawingImageView.bounds.size, NO, 0.0);

        [self.drawingImageView.image drawAtPoint:CGPointZero];
        [color setStroke];
        [path stroke];
        self.drawingImageView.image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    });
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIBezierPath *path = [UIBezierPath bezierPath];

    if (self.ctr == 0)
    {
        [path moveToPoint:pts[0]];
        [path addLineToPoint:pts[0]];
    }

    self.undoButton.hidden = NO;
    [self.undoButton setTintColor:self.inkColor];

     if (!self.drawingPathArray)
     {
        self.drawingPathArray = [[NSMutableArray alloc]init];
     }

     [self.drawingPathArray addObject:@[self.inkColor,path]];

     [self drawWithPath:path andColor:self.inkColor];
}

回答1:


You don't clear self.drawingImageView.image before you start doing your redraw of the remaining paths. So, all you're currently doing is redrawing the lines over the old lines.

What you should do is:

  1. Create a single new context and draw all of the lines into it
  2. Don't draw the old image into this new context
  3. Don't use GCD to queue updates to this context, just do it inline (in the background if you want)

then, at the end, get the new image from the context (image = UIGraphicsGetImageFromCurrentImageContext()) and save it in self.drawingImageView.image = image;


Pseudo code:

// create a new bitmap image context
UIGraphicsBeginImageContextWithOptions(...
ctx = UIGraphicsGetCurrentContext();

for (NSArray *subArray in self.drawingPathArray) {
    // get the path and colour
    CGContextSetStrokeColor(ctx, ...
    CGContextAddPath(ctx, ... (path from bezier)
    CGContextStrokePath(ctx);
}

// create image
image = UIGraphicsGetImageFromCurrentImageContext();

self.drawingImageView.image = image;


来源:https://stackoverflow.com/questions/22124385/uibezierpath-undo-drawing-redraw-uiimageviews-image

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!