I'm trying to create a simple paint app.
- (void)handleSingleTap:(UIPanGestureRecognizer *)recognizer
{
CGPoint location = [recognizer locationInView:[recognizer.view superview]];
NSLog(#"Test");
CGFloat ok = 40;
self.sheet.test = ok;
[self.sheet addPoint: location];
//Do stuff here...
}
This function draws lines but when I lift up my finger and replace it there is a "straight line" from the last point to the next one. How can I skip this?
Try controlling it using UIGestureRecognizerStateEnded
if(recognizer.state == UIGestureRecognizerStateEnded){
//Drawing Ends.
isDrawn = NO;
}
with your comments, I understood that you are controlling your line drawing method with a variable isDrawn.
if(recognier.state == UIGestureStateBegan){
[self moveToPoint:point]; // declare the point variable in the header file.
isDrawn = YES;
//Drawing Starts
}
Hope below code snippet helps
typedef NS_ENUM(NSInteger, PenType){
kPenTypeGreen,
kPenTypeCyan,
kPenTypeRed,
kPenTypePurple,
kPenTypeErase
};
#interface MCStylus() {
PenType penType;
CGPoint lastPoint;
CGPoint secondLastPoint;
NSInteger currentStylistPageIndex;
NSMutableArray *arrayOfStylistImages;
}
#property (nonatomic, strong) IBOutlet UIImageView *handwritingView;
#property (nonatomic, strong) UIImageView *drawImage;
- (void)initializeUI {
arrayOfStylistImages = [[NSMutableArray alloc] init];
[arrayOfStylistImages addObject:[[UIImage alloc] init]];
self.drawImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.handwritingView.frame.size.width, self.handwritingView.frame.size.height)];
self.drawImage.userInteractionEnabled = true;
self.handwritingView.backgroundColor = [UIColor whiteColor];
self.handwritingView.layer.cornerRadius = 5.0f;
self.handwritingView.layer.borderColor = [UIColor colorWithWhite:230.0f/255.0f alpha:1.0].CGColor;
self.handwritingView.layer.borderWidth = 2.0f;
self.handwritingView.clipsToBounds = true;
[self.handwritingView addSubview:self.drawImage];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
NSArray *allTouches = [touches allObjects];
int count = [allTouches count];
if(count==1){
UITouch *touch = [touches anyObject];
lastPoint = [touch locationInView:self.handwritingView];
secondLastPoint = lastPoint;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
NSArray *allTouches = [touches allObjects];
int count = [allTouches count];
if(count==1){
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.handwritingView];
UIGraphicsBeginImageContext(self.handwritingView.frame.size);
if(self.drawImage.image!=NULL)
[self.drawImage.image drawInRect:CGRectMake(0, 0, self.handwritingView.frame.size.width, self.handwritingView.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 2.0);
switch (penType) {
case kPenTypeGreen:
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 1.0, 0.0, 1.0);
break;
case kPenTypeCyan:
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 1.0, 1.0);
break;
case kPenTypeRed:
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
break;
case kPenTypePurple:
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.5, 0.2, 0.3, 1.0);
break;
case kPenTypeErase:
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 6.0 * (self.handwritingView.frame.size.height/350));
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeClear);
CGContextSetStrokeColorWithColor(UIGraphicsGetCurrentContext(),[UIColor clearColor].CGColor);
break;
default:
break;
}
CGPoint mid1 = CGPointMake((lastPoint.x+secondLastPoint.x)/2, (lastPoint.y + secondLastPoint.y)/2);
CGPoint mid2 = CGPointMake((lastPoint.x+currentPoint.x)/2, (lastPoint.y+currentPoint.y)/2);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), mid1.x, mid1.y);
CGContextAddQuadCurveToPoint(UIGraphicsGetCurrentContext(),lastPoint.x, lastPoint.y,mid2.x,mid2.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
secondLastPoint = lastPoint;
lastPoint = currentPoint;
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesEnded:touches withEvent:event];
if(self.drawImage.image!=NULL)
[arrayOfStylistImages replaceObjectAtIndex:currentStylistPageIndex withObject:self.drawImage.image];
}
Related
I'm working on a Drawing application where I need to achieve pencil effect similar to Apple notes app.
So I subclasses the UIView and write the following code.
CGPoint midPoint(CGPoint p1, CGPoint p2)
{
return CGPointMake((p1.x + p2.x) * 0.5, (p1.y + p2.y) * 0.5);
}
#interface DrawingView () {
CGPoint currentPoint;
CGPoint previousPoint1;
CGPoint previousPoint2;
CGMutablePathRef path;
}
#end
#implementation DrawingView
- (id)init
{
self = [super init];
if (self != nil) {
path = CGPathCreateMutable();
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
previousPoint1 = [touch previousLocationInView:self];
currentPoint = [touch locationInView:self];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
previousPoint2 = previousPoint1;
previousPoint1 = [touch previousLocationInView:self];
currentPoint = [touch locationInView:self];
CGPoint mid1 = midPoint(previousPoint1, previousPoint2);
CGPoint mid2 = midPoint(currentPoint, previousPoint1);
CGMutablePathRef subpath = CGPathCreateMutable();
CGPathMoveToPoint(subpath, NULL, mid1.x, mid1.y);
CGPathAddQuadCurveToPoint(subpath, NULL, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y);
CGRect bounds = CGPathGetBoundingBox(subpath);
CGPathAddPath(path, NULL, subpath);
CGPathRelease(subpath);
[self setNeedsDisplayInRect:bounds];
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddPath(context, path);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, 5.0f);
CGContextSetStrokeColorWithColor(context, [UIColor lightGrayColor].CGColor);
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextSetAlpha(context, 1.0f);
CGContextStrokePath(context);
}
This works fine and it produces the output like the following.
But I need the output like the following picture. Similar to Apple Notes app.
Any ideas how to achieve this.
Download the pencil texture and set this image as your CGContext stroke color.
private var pencilTexture = UIColor(patternImage: UIImage(named: "pencil_texture")!)
ctx.setStrokeColor(pencilTexture.cgColor)
Hopefully, I worded the question properly. Currently I have the following code:
-(void)changeImage
{
if (CGRectContainsPoint(star1.frame, lastPoint)){
image.image = [UIImage imageNamed:#"first.png"];
}
}
The code changes the image when the mouse/finger touches the star1.frame. I would like it to change only if it touches star1.frame, star2.frame, and star3.frame (all three) in no particular order.
View Controller.h
#interface ViewController : UIViewController {
CGPoint lastPoint;
CGPoint moveBackTo;
CGPoint currentPoint;
CGPoint location;
NSDate*lastClick;
BOOL mouseSwiped;
UIImageView *drawImage2;
UIImageView *frontImage2;
IBOutlet UIImageView *letter;
IBOutlet UIImageView *star1;
IBOutlet UIImageView *star2;
}
#property BOOL hadTouchedOne;
#property BOOL hadTouchedTwo;
-(void)changeImage;
and followed by complete .m
#implementation ViewController
- (void)viewDidLoad {
letter.image = [UIImage imageNamed:#"A.png"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
drawImage2.image = [defaults objectForKey:#"drawImageKey"];
drawImage2 = [[UIImageView alloc] initWithImage:nil];
drawImage2.frame = self.view.frame;
[self.view addSubview:drawImage2];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
if ([touch tapCount] == 3 ) {
drawImage2.image = nil;
}
location = [touch locationInView: touch.view];
lastClick = [NSDate date];
lastPoint = [touch locationInView: self.view];
lastPoint.y -= 0;
[super touchesBegan: touches withEvent: event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
currentPoint = [touch locationInView: self.view];
UIGraphicsBeginImageContext(CGSizeMake(1028, 1028));
[drawImage2.image drawInRect:CGRectMake(0, 0, 1028, 1028)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 26/255.0f, 188/255.0f, 156/255.0f, 1);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
[drawImage2 setFrame: CGRectMake(0, 0, 1028, 1028)];
drawImage2.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;
[self.view addSubview:drawImage2];
[self changeImage];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)changeImage {
if (CGRectContainsPoint(star1.frame, lastPoint)) self.hadTouchedOne = YES;
if (CGRectContainsPoint(star2.frame, lastPoint)) self.hadTouchedOne = YES;
if (_hadTouchedOne && _hadTouchedTwo) {
letter.image = [UIImage imageNamed:#"B.png"];
}
}
Edit:
#property BOOL hadTouchedOne;
#property BOOL hadTouchedTwo;
#property BOOL hadTouchedThree;
if (CGRectContainsPoint(star1.frame, lastPoint)){
self.hadTouchedOne = YES;
}
else if (CGRectContainsPoint(star2.frame, lastPoint)){
self.hadTouchedTwo = YES;
}
if (_hadTouchedOne && _hadTouchedTwo) {
[letter setImage:[UIImage imageNamed:#"B.png"]];
}
In this case, I use else if to trigger the flag.
I noticed that there is a typo in your code which there are two hadTouchedOne in your code. Now, it may work.
I have implemented the following code which allows the user to draw on an imageView. I would like to implement this throughout my app but would prefer not to keep copying and pasting.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
pointCurrent = [touch locationInView:self.view];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint pointNext = [touch locationInView:self.view];
UIGraphicsBeginImageContext(drawImage.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, drawImage.frame.size.width, drawImage.frame.size.height)];
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 2.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, 0.0, 1.0);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), pointCurrent.x, pointCurrent.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), pointNext.x, pointNext.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
pointCurrent = pointNext;
}
So far I have tried to create a category but I'm unsure if this is the right way to go about it. Do I make a custom method and try to call that in the other classes or am I barking up the wrong tree? Thanks in advance for taking the time to read this question.
I modified your code a little, because I was getting that same error that you mention in your comment. This code worked for me.
#interface RDImageView ()
#property (nonatomic) CGPoint pointCurrent;
#end
#implementation RDImageView
-(instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
self.userInteractionEnabled = YES;
self.backgroundColor = [UIColor blueColor];
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
self.pointCurrent = [touch locationInView:self];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint pointNext = [touch locationInView:self];
UIGraphicsBeginImageContext(self.frame.size);
[self.image drawInRect:self.bounds];
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 2.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1,1, 0.0, 1.0);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), self.pointCurrent.x, self.pointCurrent.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), pointNext.x, pointNext.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.pointCurrent = pointNext;
}
The below code is working fine in ARC but it is not working in non arc , actually i want to implement this free hand drawing in non arc code. The problem in non arc is the pointer is at one place and the line is drawing in another place.here is the screen shot for your
reference
Code:
in .h
UIImageView *drawImage;
CGPoint location;
CGPoint lastPoint;
CGPoint moveBackTo;
CGPoint currentPoint;
NSDate *lastClick;
BOOL mouseSwiped;
NSMutableArray *latLang;
///
- (void)viewDidLoad
{
[super viewDidLoad];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
drawImage.image = [defaults objectForKey:#"drawImageKey"];
drawImage = [[UIImageView alloc] initWithImage:nil];
drawImage.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
[self.view addSubview:drawImage];
drawImage.backgroundColor = [UIColor blueColor];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
if ([touch tapCount] == 2) {
drawImage.image = nil;
}
location = [touch locationInView:self.view];
lastClick = [NSDate date];
lastPoint = [touch locationInView:self.view];
NSLog(#"LastPoint:%#",NSStringFromCGPoint(lastPoint));
lastPoint.y -= 0;
mouseSwiped = YES;
[super touchesBegan: touches withEvent: event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
currentPoint = [touch locationInView:self.view];
UIGraphicsBeginImageContext(CGSizeMake(self.view.frame.size.width, self.view.frame.size.height));
[drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 8.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0, 1, 0, 1);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
[drawImage setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if (mouseSwiped) {
}
lastPoint = currentPoint;
[self.view addSubview:drawImage];
}
I suppose problem is with automatic release of lastClick. Easiest thing can be replacing:
NSDate *lastClick;
with
#property (strong, nonatomic) NSDate *lastClick;
... Ok I have confused ARC and no ARC. As you have problem with no ARC then you must retain date:
lastClick = [[NSDate date] retain];
and then add handler for touchesEnd with implementation:
[lastClick release];
lastClick = nil;
user touch and drag on top of image
i had this code that will give me circle after drawing but how do i space apart them ?
//UIView CircleView
- (void) touchesBegan:(NSSet *) touches withEvent:(UIEvent *) event
{
NSLog(#"started");
// Initialize a new path for the user gesture
self.path = [UIBezierPath bezierPath];
self.path.lineWidth = 4.0f;
self.whiteCircleArray = [[NSMutableArray alloc]init];
UITouch *touch = [touches anyObject];
[self.path moveToPoint:[touch locationInView:self]];
self.touchedEnded = FALSE;
}
- (void) touchesMoved:(NSSet *) touches withEvent:(UIEvent *) event
{
// Add new points to the path
NSLog(#"Moved");
UITouch *touch = [touches anyObject];
//NSLog(#"[touch locationInView:self] %#",NSStringFromCGPoint([touch locationInView:self]));
[self.whiteCircleArray addObject: NSStringFromCGPoint([touch locationInView:self])];
[self.path addLineToPoint:[touch locationInView:self]];
//double startAngle = RADIANS(0);
//double endAngle = RADIANS(360);
// if ([touch locationInView:self].x <=200 )
// {
// [self.path addArcWithCenter:[touch locationInView:self] radius:LARGE_RADIUS startAngle:startAngle endAngle:endAngle clockwise:NO];
// }
// else if ([touch locationInView:self].x >=120 )
// {
// [self.path addArcWithCenter:[touch locationInView:self] radius:SMALL_RADIUS startAngle:startAngle endAngle:endAngle clockwise:NO];
// }
//[self.path addArcWithCenter:[touch locationInView:self] radius:BIG_RADIUS startAngle:startAngle endAngle:endAngle clockwise:NO];
//[self.path addArcWithCenter:[touch locationInView:self] radius:MIDDIUM_RADIUS startAngle:startAngle endAngle:endAngle clockwise:NO];
[self setNeedsDisplay];
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"ended");
UITouch *touch = [touches anyObject];
//[self.path addLineToPoint:[touch locationInView:self]];
self.locationOfTouch =[touch locationInView:self];
self.touchedEnded = TRUE;
//NSLog(#"white circle pos %#",self.whiteCircleArray);
for(NSString *p in self.whiteCircleArray)
{
CGPoint point = CGPointFromString(p);
NSLog(#"X=%0.1f Y=%0.1f",point.x,point.x);
}
[self setNeedsDisplay];
}
- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"cancelled");
[self touchesEnded:touches withEvent:event];
}
-(void)drawTouchCircle
{
CGContextRef ctx= UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextSetLineWidth(ctx,1);
CGContextSetRGBFillColor(ctx, 55.0/255, 255.0/255.0, 5.0/255.0, 1.0);
CGContextSetRGBStrokeColor(ctx,0.0/255,0.0/255,0.0/255,1.0);
for(NSString *p in self.whiteCircleArray)
{
CGPoint point = CGPointFromString(p);
NSLog(#"X=%0.1f Y=%0.1f",point.x,point.x);
CGContextAddArc(ctx, point.x, point.y, LARGE_RADIUS, 0, M_PI*2, YES);
CGContextFillPath(ctx);
CGContextStrokePath(ctx);
}
}
- (void) drawRect:(CGRect)rect
{
// Draw the path
NSLog(#"drawRect");
if (self.touchedEnded)
{
[self drawTouchCircle];
}
else
{
UIColor *strokeColor = [UIColor redColor];
[strokeColor setStroke];
[self.path stroke];
}
// [self.path fill];
//[self.path closePath];
}
Put a distance check in your algo... CGPoint diff = {p2.x - p1.x, p2.y - p1.y} If the diff is greater than , add a new point.