如何撤消描边iOS [英] How to undo a line stroke ios

查看:131
本文介绍了如何撤消描边iOS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个着色应用程序,但是我无法实现一个UNDO按钮.我不确定该方法,我尝试实现NSUndoManager,但无法使其有效工作.我的方法可能不正确.根据我的示例,我将非常感谢使用代码的答案.

Im developing a colouring app, however I cant manage to implement an UNDO button. I am unsure of the approach, I have tried implementing NSUndoManager, but I could not get it to work effectively. My approach is possibly incorrect. Im would greatly appreciate an answer that uses code, based on my example.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    mouseSwiped = NO;
    UITouch *touch = [touches anyObject];
    lastPoint = [touch locationInView:self.view];
}  

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

   mouseSwiped = YES;
   UITouch *touch = [touches anyObject];
   CGPoint currentPoint = [touch locationInView:self.view];

   UIGraphicsBeginImageContext(self.view.frame.size);
   [self.tempImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];

   //get the current touch point and then draw a line with CGContextAddLineToPoint from lastPoint to currentPoint. You’re right to think that this approach will produce a series of straight lines, but the lines are sufficiently short that the result looks like a nice smooth curve.
   CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
   CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);


   //Now set our brush size and opacity and brush stroke color:
   CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
   CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush );
   CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
   CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
   //Finish it off by drawing the path:
   CGContextStrokePath(UIGraphicsGetCurrentContext());

   self.tempImage.image = UIGraphicsGetImageFromCurrentImageContext();
   [self.tempImage setAlpha:opacity];
   UIGraphicsEndImageContext();

   lastPoint = currentPoint;
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

/*
 check if mouse was swiped. If it was, then it means touchesMoved was called and you don’t need to draw any further. However, if the mouse was not swiped, then it means user just tapped the screen to draw a single point. In that case, just draw a single point.

 */
   if(!mouseSwiped) {
       UIGraphicsBeginImageContext(self.view.frame.size);
       [self.tempImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
       CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
       CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush);
       CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, opacity);
       CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
       CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
       CGContextStrokePath(UIGraphicsGetCurrentContext());
       CGContextFlush(UIGraphicsGetCurrentContext());
       self.tempImage.image = UIGraphicsGetImageFromCurrentImageContext();
       UIGraphicsEndImageContext();
   }

   UIGraphicsBeginImageContext(self.mainImage.frame.size);
   [self.mainImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width,  self.view.frame.size.height) blendMode:kCGBlendModeNormal alpha:1.0];
   [self.tempImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) blendMode:kCGBlendModeNormal alpha:opacity];

   //Once the brush stroke is done, merge the tempDrawImage with mainImage,
   self.mainImage.image = UIGraphicsGetImageFromCurrentImageContext();
   self.tempImage.image = nil;
   UIGraphicsEndImageContext();
}

有人问过类似的问题,但没有给出明确的答案,还有一些未得到回答.

There has been similar questions asked but no clear answer was given, and a few left unanswered.

*编辑1基于gabbler答案*

#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *mainImage;
@property (weak, nonatomic) IBOutlet UIImageView *tempImage;
@property (weak, nonatomic) IBOutlet UIImageView *palette;
@property (nonatomic) UIImage * previousImage;
@property (nonatomic,readonly) NSUndoManager * undoManager;
- (IBAction)colorPressed:(id)sender;
- (IBAction)erase:(id)sender;

- (IBAction)undo:(id)sender;
@end


@implementation ViewController

//gabbler code
- (void)setImage:(UIImage*)currentImage fromImage:(UIImage*)preImage
{
    // Prepare undo-redo
   [[self.undoManager prepareWithInvocationTarget:self] setImage:preImage fromImage:currentImage];
   self.mainImage.image = currentImage;
   self.tempImage.image = currentImage;
   self.previousImage = currentImage;
}
- (IBAction)trash:(id)sender {
     self.mainImage.image = nil;
}


- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    red = 0.0/255.0;
    green = 0.0/255.0;
    blue = 0.0/255.0;
    brush = 10.0;
    opacity = 1.0;

    //gabbler code
    self.previousImage = self.tempImage.image;
}



- (IBAction)erase:(id)sender {

    //set it to background color
    red = 255.0/255.0;
    green = 255.0/255.0;
    blue = 255.0/255.0;
    opacity = 1.0;

}
//gabbler code
- (IBAction)undo:(id)sender {
    [self.undoManager undo];
}

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

    mouseSwiped = NO;
    UITouch *touch = [touches anyObject];
    lastPoint = [touch locationInView:self.view];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    mouseSwiped = YES;
    UITouch *touch = [touches anyObject];
    CGPoint currentPoint = [touch locationInView:self.view];

    UIGraphicsBeginImageContext(self.view.frame.size);
    [self.tempImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];

    //get the current touch point and then draw a line with CGContextAddLineToPoint from lastPoint to currentPoint. You’re right to think that this approach will produce a series of straight lines, but the lines are sufficiently short that the result looks like a nice smooth curve.
    CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
    CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);


    //Now set our brush size and opacity and brush stroke color:
    CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
    CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush );
    CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
    CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
    //Finish it off by drawing the path:
    CGContextStrokePath(UIGraphicsGetCurrentContext());

    self.tempImage.image = UIGraphicsGetImageFromCurrentImageContext();
    [self.tempImage setAlpha:opacity];
    UIGraphicsEndImageContext();

    lastPoint = currentPoint;
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {


    /*
     check if mouse was swiped. If it was, then it means touchesMoved was called and you don’t need to draw any further. However, if the mouse was not swiped, then it means user just tapped the screen to draw a single point. In that case, just draw a single point.

     */
    if(!mouseSwiped) {
        UIGraphicsBeginImageContext(self.view.frame.size);
        [self.tempImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
        CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
        CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush);
        CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, opacity);
        CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
        CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
        CGContextStrokePath(UIGraphicsGetCurrentContext());
        CGContextFlush(UIGraphicsGetCurrentContext());
        self.tempImage.image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    }

    UIGraphicsBeginImageContext(self.mainImage.frame.size);
    [self.mainImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) blendMode:kCGBlendModeNormal alpha:1.0];
    [self.tempImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width,    self.view.frame.size.height) blendMode:kCGBlendModeNormal alpha:opacity];

    //Once the brush stroke is done, merge the tempDrawImage with mainImage,
    self.mainImage.image = UIGraphicsGetImageFromCurrentImageContext();
    self.tempImage.image = nil;
    UIGraphicsEndImageContext();

    //gabbler code
    UIImage *currentImage = UIGraphicsGetImageFromCurrentImageContext();
    [self setImage:currentImage fromImage:currentImage];
 }
 @end

推荐答案

UIViewController的超类UIResponder具有NSUndoManager属性,可在此处使用.上面的代码为imageView执行了设置图像操作,要撤消该操作,您必须保留对设置为imageView的先前图像的引用.您可以在viewDidLoad中设置一个名为previousImage的实例变量,设置

UIViewController's superclass UIResponder has a NSUndoManager property, which can be used here. The above code performs a setting image action for the imageView, to undo the action, you have to keep a reference of the previous image that was set to the imageView. You can make an instance variable called previousImage, in viewDidLoad, set

previousImage = self.tempImage.image;

这是为UIImageView设置图像的功能.

And here is the function to set image for UIImageView.

- (void)setImage:(UIImage*)currentImage fromImage:(UIImage*)preImage
{
    // Prepare undo-redo
    [[self.undoManager prepareWithInvocationTarget:self] setImage:preImage fromImage:currentImage];
    self.mainImage.image = currentImage;
    self.tempImage.image = currentImage;
    previousImage = currentImage;
}

touchesEnded中.

UIImage *currentImage = UIGraphicsGetImageFromCurrentImageContext();
[self setImage:currentImage fromImage:previousImage];

当您单击要撤消的按钮时.

When you click a button for undoing.

- (IBAction)btnClicked:(id)sender {
    [self.undoManager undo];
}

编辑

上述方法将导致内存问题,请不要将图像保存在undoManager中,而是保存行路径点,这是

The above method will cause memory issues, don't save images in undoManager, save the line path points instead, here is a sample project with undo and redo capabilities.

这篇关于如何撤消描边iOS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆