ぬりえアプリを開発していますが、UNDO ボタンを実装できません。NSUndoManager を実装しようとしましたが、効果的に機能させることができませんでした。私のアプローチはおそらく間違っています。私の例に基づいて、コードを使用した回答をいただければ幸いです。
- (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();
}
同様の質問がありましたが、明確な回答は得られず、未回答のものがいくつかありました。
*ガブラーの回答に基づく編集1 *
#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