So I am a fresh iOS developer working on an iOS drawing application that plays back user sketches using x/y coordinates and timestamps. To draw simple pen events i have a UIView that serves as the drawing view and I draw to the view using CAShapeLayers like so:
if (index == 0){
CGPathMoveToPoint(path, NULL, point.x, point.y);
} else {
CGPathAddLineToPoint(path, NULL, point.x, point.y);
}
……
CAShapeLayer *permLayer = [CAShapeLayer layer];
[permLayer setFrame:CGRectMake(0, 0, 1024, 640)];
[permLayer setFillColor:[[UIColor clearColor] CGColor]];
[permLayer setStrokeColor:currentColor.CGColor];
[permLayer setLineWidth:[event[@"strokeWeight"] floatValue]];
[permLayer setLineJoin:kCALineJoinRound];
[permLayer setLineCap:kCALineCapRound];
……
[[self layer] addSublayer:permLayer];
……
All is good and it looks fine:
Now what I want to do is have an erase event that looks like:
I tried to accomplish this using another CAShapeLayer as a mask and drawing the CGPath of the erase event to that mask. However what I ended up with was this:
….which is the exact opposite of what I want. I guess I need to somehow get the inverse mask of the CAShapeLayer created by the CGPath of the erase event? I’m not sure what the proper way to approach this would be without a lot of math that I’m not familiar with.
The other caveat is that this animation is tied to CADisplayLink so these drawing animations are being refreshed very often and performance is important. I’ve tried before with drawing to UIImages instead of CAShapeLayers and using kCGBlendModeClear to achieve the erase effect, but performance suffered terribly. Thanks for any advice or insights!
I guess I need to somehow get the inverse mask of the CAShapeLayer created by the CGPath of the erase event?
The "inverse mask" you ask for is not something that can be described by a CAShapeLayer
(at least there's no straightforward solution). If you want to stay with CAShapeLayer
, add the "erase path" with the background color of the image.
However, if I understand your implementation correctly, I see another problem: You add a sublayer for each stroke the user does. If the user draws complex pictures with many strokes, you will end up with a huge stack of layers which will for sure lead to performance problems at some point.
I would suggest switch to another approach and draw to an image buffer. It sounds like you tried it but dismissed the approach due to performance reasons - but if done correctly, the performance is pretty good.
Create your own bitmap context with
_context = CGBitmapContextCreate(...);
and in your touchesBegan/Moved methods draw to that context like this:
if(isEraseEvent)
CGContextSetBlendMode(_context, kCGBlendModeClear);
else
CGContextSetBlendMode(_context, kCGBlendModeNormal);
// Configure your current stroke: lineWidth, color etc.
CGContextSetLineWidth(_context, _currentStroke.lineWidth);
// Added stroke from point p to point q
CGContextMoveToPoint(_context, p.x, p.y);
CGContextAddLineToPoint(_context, q.x, q.y);
CGContextStrokePath(_context);
After each such event, display the context. You could render the whole context to a UIImage and display the UIImage, but the performance might suffer this way. Instead, let the rendering be done by a CALayer with a delegate. Have the delegate implement the method
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
CGImageRef tempImage = CGBitmapContextCreateImage(_context);
CGContextDrawImage(ctx, self.bounds, tempImage);
CGImageRelease(tempImage);
}
Don't forget to tell the layer that its content changed whenever you draw to the context. Calling setNeedsDisplay
redisplays the complete layer, which is most of the times way more than you need. Do something like this instead:
CGRect r = CGRectMake(MIN(p.x, q.x),
MIN(p.y, q.y),
ABS(p.x-q.x),
ABS(p.y-q.y));
CGFloat inset = ...;
[_theLayer setNeedsDisplayInRect:CGRectInset(r, inset, inset)];
to ensure you rerender only the part of the image where the content actually changed. inset
should be some (negative) inset to take your stroke width into account.
Note that all the stuff I've written above (except context creation) is called once for every touchesMoved
event, i.e. the strokes are rendered and displayed at the moment the user inputs them (or, as in you case, the drawing process is replayed) and you never need to render or display more than that.
My approach was to build undo and redo stacks. The code is below.. It's a bit more than you asked for, but maybe others will a) find it useful, and b) tell me how to improve it..
viewController:
#define kBrushOpacity (1.0 / 3.0)
#define kBrushPixelStep 3
#define kBrushScale 3
#define kLuminosity 0.75
#define kSaturation 1.0
#define kPaletteHeight 30
#define kPaletteSize 25
#define kMinEraseInterval 0.5
// Padding for margins
#define kLeftMargin 10.0
#define kTopMargin 50.0
#define kRightMargin 10.0
#define kBottomMargin 550.0
#define kCGBlendModePlusLighter 30.0
CGImageRef UIGetScreenImage(void);
@implementation DrawingViewController
- (IBAction)dismiss:(id)sender {
//NSLog(@"%s", __FUNCTION__);
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)viewDidLoad
{
//NSLog(@"%s", __FUNCTION__);
[super viewDidLoad];
pathArray=[[NSMutableArray alloc]init];
bufferArray=[[NSMutableArray alloc]init];
tempArray=[[NSMutableArray alloc]init];
orientation = [[UIApplication sharedApplication] statusBarOrientation];
[self.window addSubview:window];
[self.window makeKeyAndVisible];
drawingView =[[DrawingView alloc]initWithFrame:CGRectMake (0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
drawingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[drawingView setBackgroundColor:[UIColor blackColor]];
//[self backgroundSwitchChange];
[self.view addSubview:drawingView];
rect = [[UIScreen mainScreen] bounds];
brushSize = [[NSUserDefaults standardUserDefaults] valueForKey:@"brushKey"];
moved = 0;
[self buildColorBar];
[self buildToolBar];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(brushChange) name:@"brushNotification" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pictureChange) name:@"pictureNotification" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backgroundSwitchChange) name:@"backgroundNotification" object:nil];
[self showAlert];
UIGraphicsBeginImageContext(self.view.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
savedImage.image = drawImage.image;
UIGraphicsEndImageContext();
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
//NSLog(@"%s", __FUNCTION__);
return YES;
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
//NSLog(@"%s", __FUNCTION__);
[toolControls removeFromSuperview];
[colorControls removeFromSuperview];
[self buildColorBar];
[self buildToolBar];
}
- (void)setupNotifications {
//NSLog(@"%s", __FUNCTION__);
NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
[dnc addObserver:self selector:@selector(brushChange) name:@"brushChange:" object:nil];
[dnc addObserver:self selector:@selector(brushColorChange) name:@"createColorNotification" object:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - Top Toolbar
-(void) buildToolBar {
//NSLog(@"%s", __FUNCTION__);
toolControls = [[UISegmentedControl alloc] initWithItems:
[NSArray arrayWithObjects:
[UIImage imageNamed:@"Brush.png"],
[UIImage imageNamed:@"Undo.png"],
[UIImage imageNamed:@"Redo.png"],
[UIImage imageNamed:@"Save.png"],
[UIImage imageNamed:@"Erase.png"],
[UIImage imageNamed:@"Restore.png"],
nil]];
UIInterfaceOrientation fieldOrient = [[UIApplication sharedApplication] statusBarOrientation];
if ((fieldOrient == UIDeviceOrientationLandscapeLeft) || (fieldOrient == UIDeviceOrientationLandscapeRight)) {
//NSLog(@"Landscape");
CGRect frame = CGRectMake(0, 30, 480, 25 );
toolControls.frame = frame;
} else {
//NSLog(@"Portrait");
CGRect frame = CGRectMake(0, 30, 320, 25 );
toolControls.frame = frame;
}
[toolControls addTarget:self action:@selector(drawSegmentAction:) forControlEvents:UIControlEventValueChanged];
toolControls.momentary = YES;
toolControls.tintColor = [UIColor grayColor];
[self.view addSubview:toolControls];
}
- (IBAction)drawSegmentAction:(id)sender
{
//NSLog(@"%s", __FUNCTION__);
UISegmentedControl *segmentedControl = (UISegmentedControl *)sender;
switch (segmentedControl.selectedSegmentIndex){
case 0: { //Brushes
[self showBrushes:sender];
break;
}
case 1: { // Undo
[drawingView undoButtonClicked];
break;
}
case 2: { // Redo
[drawingView redoButtonClicked];
break;
}
case 3: { // Save
[self saveButtonTapped:self];
break;
}
case 4: { // Erase
[self eraseButtonTapped:self];
break;
}
case 5: { // Restore
[self restoreButtonTapped:self];
break;
}
default: {
//NSLog(@"default");
break;
}
}
}
- (void)doneButtonTapped {
[delegate doneButtonTapped];
}
#pragma mark - Color Bar
-(void) buildColorBar {
//NSLog(@"%s", __FUNCTION__);
colorControls = [[UISegmentedControl alloc] initWithItems:
[NSArray arrayWithObjects:
[UIImage imageNamed:@"White.png"],
[UIImage imageNamed:@"Red.png"],
nil]];
UIInterfaceOrientation fieldOrient = [[UIApplication sharedApplication] statusBarOrientation];
if ((fieldOrient == UIDeviceOrientationLandscapeLeft) || (fieldOrient == UIDeviceOrientationLandscapeRight)) {
CGRect frame = CGRectMake(0, 230, 480, 25 );
colorControls.frame = frame;
} else {
CGRect frame = CGRectMake(0, 390, 320, 25 );
colorControls.frame = frame;
}
// Add LongTap Color options
gesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(showMoreColors:)];
gesture.minimumPressDuration = 1.0;
[colorControls addGestureRecognizer:gesture];
//gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showMoreColors:)];
//[gesture setNumberOfTapsRequired:2];
//[colorControls addGestureRecognizer:gesture];
// When the user chooses a color, the method changeColor: is called.
[colorControls addTarget:self action:@selector(changeColor:) forControlEvents:UIControlEventValueChanged];
colorControls.segmentedControlStyle = UISegmentedControlStyleBar;
// Make sure the color of the color complements the black background
colorControls.tintColor = [UIColor grayColor];
// Add the control to the window
[self.view addSubview:colorControls];
}
// Change the brush color
- (IBAction)changeColor:(id)sender {
//NSLog(@"%s", __FUNCTION__);
colorIndex = [sender selectedSegmentIndex];
AppDelegate *mainDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
mainDelegate.colorIndex = colorIndex;
switch (colorIndex) {
case 0:
colorKey = @"0";
break;
case 1:
colorKey = @"1";
break;
case 2:
colorKey = @"2";
break;
case 3:
colorKey = @"3";
break;
default:
break;
}
[[NSUserDefaults standardUserDefaults] setObject: colorKey forKey: @"colorKey"];
[[NSNotificationCenter defaultCenter] postNotificationName: @"ColorChange" object: nil];
[drawingView changeColor:sender];
}
-(void) showMoreColors:(id)sender {
//NSLog(@"%s", __FUNCTION__);
switch (colorIndex) {
case 0:
[self showMoreWhiteColors:(id)sender];
break;
case 1:
[self showMoreRedColors:(id)sender];
break;
case 2:
[self showMoreYellowColors:(id)sender];
break;
case 3:
[self showMoreGreenColors:(id)sender];
break;
case 4:
[self showMoreBlueColors:(id)sender];
break;
case 5:
[self showMorePurpleColors:(id)sender];
break;
case 6:
[self showMoreBlackColors:(id)sender];
break;
default:
break;
}
}
#pragma mark - Brushes
//delegate methods
- (void)brushesViewControllerDidFinish:(BrushesViewController *)controller
{
//NSLog(@"%s", __FUNCTION__);
[self brushChange];
}
- (void)brushChange { //from notification
//NSLog(@"%s", __FUNCTION__);
brushSize = [[NSUserDefaults standardUserDefaults] objectForKey:@"brushKey"];
[drawingPath brushChange];
}
- (IBAction)showBrushes:(id)sender
{
//NSLog(@"%s", __FUNCTION__);
BrushesViewController *controller = [[BrushesViewController alloc] initWithNibName:@"Brushes" bundle:nil];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];
}
- (void)changeBrushSize:(id)sender {
//NSLog(@"%s", __FUNCTION__);
}
#pragma mark - Colors
- (void)whiteViewControllerDidFinish:(WhiteViewController *)controller
{
//NSLog(@"%s", __FUNCTION__);
[[NSNotificationCenter defaultCenter] postNotificationName: @"ColorChange" object: nil];
[drawingView changeColor:self];
}
- (void)redViewControllerDidFinish:(RedViewController *)controller
{
//NSLog(@"%s", __FUNCTION__);
[[NSNotificationCenter defaultCenter] postNotificationName: @"ColorChange" object: nil];
[drawingView changeColor:self];
}
- (void)greenViewControllerDidFinish:(GreenViewController *)controller
{
//NSLog(@"%s", __FUNCTION__);
[[NSNotificationCenter defaultCenter] postNotificationName: @"ColorChange" object: nil];
[drawingView changeColor:self];
}
- (void)purpleViewControllerDidFinish:(PurpleViewController *)controller
{
//NSLog(@"%s", __FUNCTION__);
[[NSNotificationCenter defaultCenter] postNotificationName: @"ColorChange" object: nil];
[drawingView changeColor:self];
}
- (IBAction)showMoreWhiteColors:(id)sender {
//NSLog(@"%s", __FUNCTION__);
WhiteViewController *controller = [[WhiteViewController alloc] initWithNibName:@"White" bundle:nil];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];
}
- (IBAction)showMoreRedColors:(id)sender
{
//NSLog(@"%s", __FUNCTION__);
RedViewController *controller = [[RedViewController alloc] initWithNibName:@"Red" bundle:nil];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];
}
- (IBAction)showMoreYellowColors:(id)sender {
//NSLog(@"%s", __FUNCTION__);
YellowViewController *controller = [[YellowViewController alloc] initWithNibName:@"Yellow" bundle:nil];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];
}
- (IBAction)showMoreBlackColors:(id)sender {
BlackViewController *controller = [[BlackViewController alloc] initWithNibName:@"Black" bundle:nil];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];
}
#pragma mark - Save
- (IBAction)saveButtonTapped:(id)sender
{
[self captureToPhotoAlbum];
[self flashScreen];
}
-(void)captureToPhotoAlbum {
//NSLog(@"%s", __FUNCTION__);
UIScreen *screen = [UIScreen mainScreen];
CGRect screenRect = screen.bounds; //implicitly in Portrait orientation.
UIInterfaceOrientation fieldOrient = [[UIApplication sharedApplication] statusBarOrientation];
if ((fieldOrient == UIDeviceOrientationLandscapeLeft) || (fieldOrient == UIDeviceOrientationLandscapeRight)) {
CGRect temp;
temp.size.width = screenRect.size.height;
temp.size.height = screenRect.size.width;
screenRect = temp;
}
UIGraphicsBeginImageContext(screenRect.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
[[UIColor blackColor] set];
CGContextFillRect(ctx, screenRect);
[self.view.layer renderInContext:ctx];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] && [[UIScreen mainScreen] scale] == 2.0) {
// Retina
// Image cropping This is the size of the saved image.
//NSLog(@"height is %f", self.view.bounds.size.height );
CGImageRef imageRef = CGImageCreateWithImageInRect
([img CGImage],
CGRectMake (0, 75, (self.view.bounds.size.width * 2), (self.view.bounds.size.height -130)));
// NSLog(@"width is %f", self.view.bounds.size.width * 2 );
UIImage *img2Save = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
// Request to save the image to camera roll
UIImageWriteToSavedPhotosAlbum(img2Save, self, nil, nil);
} else {
CGImageRef imageRef = CGImageCreateWithImageInRect
([img CGImage],
CGRectMake (0, 75, self.view.bounds.size.width, (self.view.bounds.size.height - 130)));
UIImage *img2Save = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
// Request to save the image to camera roll
UIImageWriteToSavedPhotosAlbum(img2Save, self, nil, nil);
}
}
-(void) flashScreen {
//NSLog(@"%s", __FUNCTION__);
UIWindow* wnd = [UIApplication sharedApplication].keyWindow;
UIView* v = [[UIView alloc] initWithFrame: CGRectMake(0, 0, wnd.frame.size.width, wnd.frame.size.height)];
[wnd addSubview: v];
v.backgroundColor = [UIColor whiteColor];
[UIView beginAnimations: nil context: nil];
[UIView setAnimationDuration: 1.0];
v.alpha = 0.0f;
[UIView commitAnimations];
}
#pragma mark - Undo Redo
-(IBAction)undoButtonTapped:(id)sender
{
//NSLog(@"%s", __FUNCTION__);
[drawingView undoButtonClicked];
}
-(IBAction)redoButtonTapped:(id)sender
{
//NSLog(@"%s", __FUNCTION__);
[drawingView redoButtonClicked];
}
#pragma mark - Erase / Restore
- (IBAction)eraseButtonTapped:(id)sender {
//NSLog(@"%s", __FUNCTION__);
savedImage.image = drawImage.image;
[drawingView eraseButtonClicked];
undoFlag = 1;
}
- (IBAction)restoreButtonTapped:(id)sender {
//NSLog(@"%s", __FUNCTION__);
if (undoFlag == 1) {
drawImage.image = savedImage.image;
[drawingView restoreButtonClicked];
undoFlag = 0;
}
}
@end
UIView:
#import "DrawingView.h"
float red = 0;
float green = 1;
float blue = 0;
float alpha = 50;
- (id)initWithFrame:(CGRect)frame
{
//NSLog(@"%s", __FUNCTION__);
if (!(self = [super initWithFrame:frame]))
return nil;
[self initializeView];
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
//NSLog(@"%s", __FUNCTION__);
if (!(self = [super initWithCoder:aDecoder]))
return nil;
[self initializeView];
return self;
}
- (void)initializeView {
_currentColor = [UIColor greenColor];
_currentArray = [NSMutableArray array];
_bufferArray = [NSMutableArray array];
_redoStack = [NSMutableArray array];
_result = @"NO";
myPath=[[UIBezierPath alloc]init];
myPath.lineCapStyle=kCGLineCapRound;
[self setUserInteractionEnabled:YES];
}
- (void)drawRect:(CGRect)rect {
//NSLog(@"%s", __FUNCTION__);
for (DrawingPath *drawingPath in self.currentArray) {
[drawingPath draw];
}
}
#pragma mark - Actions
- (void)eraseButtonClicked {
//NSLog(@"%s", __FUNCTION__);
self.bufferArray = [self.currentArray mutableCopy];
[self.currentArray removeAllObjects];
[self setNeedsDisplay];
}
- (void)restoreButtonClicked {
//NSLog(@"%s", __FUNCTION__);
self.currentArray = [self.bufferArray mutableCopy];
[self.bufferArray removeAllObjects];
[self setNeedsDisplay];
}
-(void)undoButtonClicked
{
//NSLog(@"%s", __FUNCTION__);
if ([self.currentArray count] == 0) {
//nothing to undo
return;
}
DrawingPath *undonePath = [self.currentArray lastObject];
[self.currentArray removeLastObject];
[self.redoStack addObject:undonePath];
[self setNeedsDisplay];
}
-(void)redoButtonClicked
{
//NSLog(@"%s", __FUNCTION__);
if ([self.redoStack count] == 0) {
// nothing to redo
return;
}
DrawingPath *redonePath = [self.redoStack lastObject];
[self.redoStack removeLastObject];
[self.currentArray addObject:redonePath];
[self setNeedsDisplay];
}
#pragma mark - Touch Methods
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(@"%s", __FUNCTION__);
self.currentColoredPath = [[DrawingPath alloc] init];
[self.currentColoredPath setColor:self.currentColor];
UITouch *touch= [touches anyObject];
[self.currentColoredPath.path moveToPoint:[touch locationInView:self]];
[self.currentArray addObject:self.currentColoredPath];
// Remove all paths from redo stack
[self.redoStack removeAllObjects];
lastPoint = [touch locationInView:self];
lastPoint.y -= 20;
if ([touch tapCount] == 2) {
[self alertOKCancelAction];
return;
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(@"%s", __FUNCTION__);
UITouch *touch = [touches anyObject];
[self.currentColoredPath.path addLineToPoint:[touch locationInView:self]];
[self setNeedsDisplay];
CGPoint currentPoint = [touch locationInView:self];
currentPoint.y -= 20;
lastPoint = currentPoint;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(@"%s", __FUNCTION__);
self.currentColoredPath = nil;
}
# pragma mark - Brush Colors
// Change the brush color
- (void)changeColor:(id)sender
{
//NSLog(@"%s", __FUNCTION__);
colorKey = [[NSUserDefaults standardUserDefaults] objectForKey:@"colorKey"];
colorIndex = [colorKey intValue];
switch (colorIndex) {
case 0:
red = 1;
green = 1;
blue = 1;
//[selectSound play];
break;
case 1:
red = 1;
green = 0;
blue = 0;
//[selectSound play];
break;
case 2:
red = 1;
green = 1;
blue = 0;
//[selectSound play];
break;
case 3:
red = 0;
green = 1;
blue = 0;
//[selectSound play];
break;
case 4:
red = 0.11764f;
green = 0.56470f;
blue = 1;
//[selectSound play];
break;
case 5:
red = 1;
green = 0.41176f;
blue = 0.70588f;
//[selectSound play];
break;
case 6:
red = 0;
green = 0;
blue = 0;
//[selectSound play];
break;
//WHITE
case 11:
red = 0.949020f;
green = 0.949020f;
blue = 0.949020f;
//[selectSound play];
break;
case 12:
case 13:
default:
break;
}
//NSLog(@"ColorIndex is %i", colorIndex);
self.currentColor = [UIColor colorWithRed:red green:green blue:blue alpha:1];
}
#pragma mark - Alerts
- (void)shakeOKCancelAction {
// open a alert with an OK and cancel button
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"SHAKE", nil) message: NSLocalizedString(@"SHAKEERASE", nil) delegate:self cancelButtonTitle:@"NO" otherButtonTitles:@"YES", nil];
[alert show];
}
- (void)alertOKCancelAction {
// open a alert with an OK and cancel button
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"TWICE", nil) message: NSLocalizedString(@"TAPERASE", nil) delegate:self cancelButtonTitle:@"NO" otherButtonTitles:@"YES", nil];
[alert show];
}
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
// the user clicked one of the Alert buttons
if (buttonIndex == 0)
{
return;
}
else
{
[self eraseButtonClicked];
return;
}
}
@end
and object:
@implementation DrawingPath
@synthesize path = _path;
@synthesize color = _color;
@synthesize brushSize = _brushSize;
float brush = 12;
- (id)init {
if (!(self = [super init] ))
return nil;
brushSize = [[NSUserDefaults standardUserDefaults] objectForKey:@"brushKey"];
[self brushChange];
_path = [[UIBezierPath alloc] init];
_path.lineCapStyle=kCGLineCapRound;
_path.lineJoinStyle=kCGLineJoinRound;
[_path setLineWidth:brush];
// _color = [UIColor blackColor];
return self;
}
- (void)draw {
[self.color setStroke];
[self.path stroke];
}
- (void)brushChange { //from notification
brushSize = [[NSUserDefaults standardUserDefaults] objectForKey:@"brushKey"];
//NSLog(@"DrawingPath - brushSize is %@: ", brushSize );
if (brushSize == @"128") brush = 128;
if (brushSize == @"64") brush = 64;
etc
}
@end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With