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;
Related
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];
}
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;
}
I'm exploring making a doodle app where the user draws pictures with their finger and I've come across several different ways of drawing lines to the screen. I've seen code anywhere from:
- (void)drawRect:(CGRect)rect // (5)
{
[[UIColor blackColor] setStroke];
[path stroke];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[path moveToPoint:p];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[path addLineToPoint:p]; // (4)
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesMoved:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
}
to:
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
UIGraphicsBeginImageContext(self.view.frame.size);
[self.tempDrawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brush );
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.tempDrawImage.image = UIGraphicsGetImageFromCurrentImageContext();
[self.tempDrawImage setAlpha:opacity];
UIGraphicsEndImageContext();
lastPoint = currentPoint;
and the last method (one I came up with that makes the most sense for me at least)
- (void) viewDidLoad{
UIPanGestureRecognizer* pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(drawImage:)];
[self.view addGestureRecognizer:pan];
pan.delegate = self;
paths = [[NSMutableArray alloc]init];
}
- (void) drawImage:(UIPanGestureRecognizer*)pan{
CGPoint point = [pan translationInView:self.view];
[paths addObject:[NSValue valueWithCGPoint:point]];
}
In the last implementation, I would store the points the user is dragging along and draw a line as they draw. I feel like that would be kind of intensive with a lot of overhead though since there's a lot of drawing going on while the user is interacting with the app.
So my question is, is there a best practice/best way to do drawing? Does Apple prefer a particular way over the other and what are the advantages/disadvantages of doing it each way?
A better way is to use the users touch points as points on a UIBezierPath. See session 233 WWDC 2012... http://developer.apple.com/itunes/?destination=adc.apple.com.16351493766
I want to know what's the approach to draw a line with a finger in a white view. I want to do an artboard, and I want begin to understand how draw a simple line or a track done with a finger. How can I do it?
I have understood your problem.
Please see the bellow code.It will use full for you.
-(void)intializeDrawImage
{
drawImage = [[UIImageView alloc]initWithFrame:CGRectMake(0, 100, 320, 320)];
[drawImage setBackgroundColor:[UIColor purpleColor]];
[drawImage setUserInteractionEnabled:YES];
[self.view addSubview:drawImage];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"touchesBegan");
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:drawImage];
startPoint = p;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"touchesMoved");
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:drawImage];
[self drawLineFrom:startPoint endPoint:p];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesMoved:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
}
-(void)drawLineFrom:(CGPoint)from endPoint:(CGPoint)to
{
drawImage.image = [UIImage imageNamed:#""];
UIGraphicsBeginImageContext(drawImage.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, drawImage.frame.size.width, drawImage.frame.size.height)];
[[UIColor greenColor] set];
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0f);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), from.x, from.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), to.x , to.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}