Signature.h file
#import <UIKit/UIKit.h>
#interface Signature : UIViewController
{
CGPoint firstTouch;
CGPoint lastTouch;
UIColor *pointColor;
CGRect *points;
int npoints;
CGPoint location;
// UIImageView *signatureImageView;
}
#property CGPoint firstTouch;
#property CGPoint lastTouch;
#property (nonatomic, retain) UIColor *pointColor;
#property CGRect *points;
#property int npoints;
#property (retain, nonatomic) IBOutletCollection(UIImageView) NSArray *drawSign;
#property CGPoint location;
#property (retain, nonatomic) IBOutletCollection(UIImageView) NSArray *signatureImageView;
- (IBAction)savePressed:(id)sender;
- (IBAction)clearPressed:(id)sender;
#end
Signature.m
#import "Signature.h"
#interface Signature ()
#end
#implementation Signature
#synthesize drawSign;
#synthesize signatureImageView;
#synthesize firstTouch;
#synthesize lastTouch;
#synthesize pointColor;
#synthesize points;
- (id)initWithFrame:(CGRect)frame
{
return self;
}
- (id)initWithCoder:(NSCoder *)coder
{
if(self = [super initWithCoder:coder])
{
self.npoints = 0;
}
return self;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
NSLog(#"initwithnibname");
return self;
}
- (void)viewDidLoad
{
NSLog(#"viewdidload");
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
NSLog(#"view did unload");
[self setSignatureImageView:nil];
[self setDrawSign:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"touch has began");
UITouch *touch = [touches anyObject];
self.location = [touch locationInView:self.view];
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"touches moves");
UITouch *touch = [touches anyObject];
CGPoint currentLocation = [touch locationInView:self.view];
UIGraphicsBeginImageContext(self.view.frame.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
//[self.drawSign.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(ctx, 5.0);
CGContextSetRGBStrokeColor(ctx, 1.0, 0.0, 0.0, 1.0);
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, location.x, location.y);
NSLog(#"%f x is",location.x);
NSLog(#"%f y is",location.y);
CGContextAddLineToPoint(ctx, currentLocation.x, currentLocation.y);
CGContextStrokePath(ctx);
// self.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
location = currentLocation;
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"touches ended");
UITouch *touch = [touches anyObject];
CGPoint currentLocation = [touch locationInView:self.view];
UIGraphicsBeginImageContext(self.view.frame.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
//[self.view.image drawInRect:CGRectMake(0, 0, self.frame.view.size.width, self.frame.view.size.height)];
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(ctx, 5.0);
CGContextSetRGBStrokeColor(ctx, 1.0, 0.0, 0.0, 1.0);
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, location.x, location.y);
CGContextAddLineToPoint(ctx, currentLocation.x, currentLocation.y);
CGContextStrokePath(ctx);
// self.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
location = currentLocation;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)dealloc {
[signatureImageView release];
[super dealloc];
}
- (IBAction)savePressed:(id)sender {
NSLog(#"save pressed");
}
- (IBAction)clearPressed:(id)sender {
NSLog(#"cancel pressed");
}
#end
Please find the two files, related to my project. From One view I am coming to this view. Now I need to save whatever has been drawn on it by the user. I am able to fetch the co-ordinates but unable to draw them. I have tried several attempts but neither of them seems to be working.Please find them in the Signature.m file itself in commented way. Kindly point me my mistake and correct me.
I really dont understand your question but the reason this code is wrong is in the touches part.
If you want to draw while you touch then you have to use the drawInRect method from the view you want to draw in.
If you want to draw over an image to save or present it after the user releases it then you have to create an image context on the touchesBegan, then draw on it on the touchesMoved, and finally save the result in the touchesEnded.
You can extract the result at the touchesEnded with
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
What your code is doing right now is, every time you move your finger you create a new canvas, draw on it and destroy it. When you lift your finger you create one more canvas draw on it and destroy it as well.
But im pretty sure you want to move your finger and show the result directly in the screen. For that I really recommend you google for a tutorial but basically you have to: create an array of points in the touches begin, on the touches move you add points to this array and on the touches end you add the final point to the array. MEANWHILE on the view drawInRect your code has to continuously draw the points in this array.
EDIT:
ASSUMING you have a valid UIImage (blanc canvas already initialized) at the beginning in
self.drawSign.image
Try:
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"touches moves");
UITouch *touch = [touches anyObject];
CGPoint currentLocation = [touch locationInView:self.view];
UIGraphicsBeginImageContext(self.view.frame.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
[self.drawSign.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(ctx, 5.0);
CGContextSetRGBStrokeColor(ctx, 1.0, 0.0, 0.0, 1.0);
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, location.x, location.y);
NSLog(#"%f x is",location.x);
NSLog(#"%f y is",location.y);
CGContextAddLineToPoint(ctx, currentLocation.x, currentLocation.y);
CGContextStrokePath(ctx);
self.drawSign.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
location = currentLocation;
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"touches ended");
UITouch *touch = [touches anyObject];
CGPoint currentLocation = [touch locationInView:self.view];
UIGraphicsBeginImageContext(self.view.frame.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
[self.drawSign.image drawInRect:CGRectMake(0, 0, self.frame.view.size.width, self.frame.view.size.height)];
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(ctx, 5.0);
CGContextSetRGBStrokeColor(ctx, 1.0, 0.0, 0.0, 1.0);
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, location.x, location.y);
CGContextAddLineToPoint(ctx, currentLocation.x, currentLocation.y);
CGContextStrokePath(ctx);
self.drawSign.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
location = currentLocation;
}
I am not sure if this will work, but even if it does it is a TERRIBLE WAY of doing it (performance wise).
Related
How can I clear a drawing in a subview? What should I put in my (void)clearLine below?
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Setup subview to draw a line
CGRect subviewRect = CGRectMake(0, 0, 250, 300);
Draw* _draw = [[Draw alloc] initWithFrame:subviewRect];
_draw.exclusiveTouch = NO;
_draw.backgroundColor = [UIColor clearColor];
[self addSubview:_draw];
}
return self;
}
- (void) clearLine
{
// how can I clear the drawing in Draw
}
And below is the Draw.m file, that will draw a straight line by getting the first touch as the starting point and the second touch as the ending point.
#implementation Draw
- (void)drawRect:(CGRect)rect {
CGPoint fromPoint;
CGPoint toPoint;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextMoveToPoint(context, fromPoint.x, fromPoint.y);
CGContextAddLineToPoint(context, toPoint.x, toPoint.y);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
}
// Touch event
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touchPoint = [touches anyObject];
fromPoint = [touchPoint locationInView:self];
toPoint = [touchPoint locationInView:self];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];
toPoint = [touch locationInView:self];
[self setNeedsDisplay];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];
toPoint = [touch locationInView:self];
[self setNeedsDisplay];
}
In clear line you should remove Draw view and set it nil
Draw* _draw;
- (void) clearLine
{
[_draw removeFromSuperview];
_draw=nil;
}
and to again enable drawing use
-(void) initDrawView
{
CGRect subviewRect = CGRectMake(0, 0, 250, 300);
if(_draw!=nil)
{
[_draw removeFromSuperview];
_draw=nil;
}
_draw = [[Draw alloc] initWithFrame:subviewRect];
_draw.exclusiveTouch = NO;
_draw.backgroundColor = [UIColor clearColor];
[self addSubview:_draw];
}
Draw the background color on your view,
Like if you have white background then [UIColor whiteColor];
if you have black background then [UIColor blackColor];
Make a Bool variable in Draw class
And when you want to clear all like this
- (void) clearLine
{
// Here you can clearn lines
[_draw CleanAllLines]
}
And In Draw class make the method
-(void)CleanAllLines{
isNeedToClear = YES;
[self setNeedsLayout];
}
- (void)drawRect:(CGRect)rect {
if(isNeedToClear){
isNeedToClear = NO;
return;
}
CGPoint fromPoint;
CGPoint toPoint;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextMoveToPoint(context, fromPoint.x, fromPoint.y);
CGContextAddLineToPoint(context, toPoint.x, toPoint.y);
CGContextStrokePath(context);
CGColorSpaceRelease(colorspace);
CGColorRelease(color);
}
i am making paint brush using UIBezierPath using following code.
.h File
#interface MyLineDrawingView : UIView
{
UIBezierPath *myPath;
UIColor *brushPattern;
}
#end
.m File
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:#"0010.png"]];
myPath=[[UIBezierPath alloc]init];
myPath.lineWidth=30;
brushPattern=[UIColor redColor];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
[brushPattern setStroke];
[myPath strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
// [myPath strokeWithBlendMode:kCGBlendModeSaturation alpha:1.0];
// Drawing code
//[myPath stroke];
}
#pragma mark - Touch Methods
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[myPath moveToPoint:[mytouch locationInView:self]];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[myPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
It is working well with UIView. As you can see in above custom class inherits from UIVIew. But when i am subclassing UIImageView instead of UIView I am not able to draw anything. Toches method are called but it draws nothing on the screen. Does anyone know what is wrong with this or how can i resolve this?
The reason that i want to change it to UIImageView from UIView is I want to set the image and change the color. When I use UIView and use
self.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:#"0010.png"]];
the image does not fit to view. Only part of the whole image is visible. Even if i change the content mode to UIViewContentModeScaleToFill then also whole image is not visible.
From the UIImageView documentation:
The UIImageView class is optimized to draw its images to the display. UIImageView will not call drawRect: a subclass. If your subclass needs custom drawing code, it is recommended you use UIView as the base class.
In short, drawRect can't be used in UIImageView subclasses. Add an image view as a subview or draw the image as part of your drawRect instead.
It can be done using following code:
#interface Canvas : UIImageView {
CGPoint location;
}
#property CGPoint location;
.m file
#synthesize location;
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
self.location = [touch locationInView:self];
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentLocation = [touch locationInView:self];
UIGraphicsBeginImageContext(self.frame.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
//CGContextSetBlendMode(ctx, kCGBlendModeOverlay);
[self.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetBlendMode(ctx, kCGBlendModeMultiply);
CGContextSetLineWidth(ctx, 5.0);
CGContextSetRGBStrokeColor(ctx, 1.0, 0.0, 0.0, 1.0);
//CGContextSetBlendMode(ctx, kCGBlendModeOverlay);
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, location.x, location.y);
CGContextAddLineToPoint(ctx, currentLocation.x, currentLocation.y);
CGContextStrokePath(ctx);
self.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
location = currentLocation;
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentLocation = [touch locationInView:self];
UIGraphicsBeginImageContext(self.frame.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
// CGContextSetBlendMode(ctx, kCGBlendModeOverlay);
[self.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextSetBlendMode(ctx, kCGBlendModeMultiply);
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(ctx, 5.0);
CGContextSetRGBStrokeColor(ctx, 1.0, 0.0, 0.0, 1.0);
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, location.x, location.y);
CGContextAddLineToPoint(ctx, currentLocation.x, currentLocation.y);
CGContextStrokePath(ctx);
self.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
location = currentLocation;
}
I picked up the following piece of code from a similar question but I'm not having any luck getting it to work.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"Check #1");
UITouch* touch = [touches anyObject];
self.currentPath = [UIBezierPath bezierPath];
currentPath.lineWidth = 3.0;
[currentPath moveToPoint:[touch locationInView:self.view]];
[paths addObject:self.currentPath];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[self.currentPath addLineToPoint:[touch locationInView:self.view]];
[self.view setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
[[UIColor redColor] set];
for (UIBezierPath *path in paths) {
NSLog(#"Check #2?");
[path stroke];
}
}
What I've got from it is that I need to use UIBezierPath but I'm not sure how to get it to follow my finger. I only want to draw a line, start it when the user touches down and end it where they pick up their finger.
How can I achieve this line drawing using UIBezierPath?
#import <UIKit/UIKit.h>
#interface Canvas : UIImageView
#property (nonatomic, assign) CGPoint location;
#end
#import "Canvas.h"
#implementation Canvas
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
self.location = [touch locationInView:self];
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentLocation = [touch locationInView:self];
UIGraphicsBeginImageContext(self.frame.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
[self.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(ctx, 5.0);
CGContextSetRGBStrokeColor(ctx, 1.0, 0.0, 0.0, 1.0);
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, self.location.x, self.location.y);
CGContextAddLineToPoint(ctx, currentLocation.x, currentLocation.y);
CGContextStrokePath(ctx);
self.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.location = currentLocation;
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentLocation = [touch locationInView:self];
UIGraphicsBeginImageContext(self.frame.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
[self.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(ctx, 5.0);
CGContextSetRGBStrokeColor(ctx, 1.0, 0.0, 0.0, 1.0);
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, self.location.x, self.location.y);
CGContextAddLineToPoint(ctx, currentLocation.x, currentLocation.y);
CGContextStrokePath(ctx);
self.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.location = currentLocation;
}
#end
I am making a little animation type of app for a project. I have a space to draw images on an imageView. Then when you click the new page button I need the image in that imageview to move into another imageview I have on the timeline. Hopefully you understand my problem if not let me know what other information you need.
hai Check This code This will allow you to draw any image and then you can access your image using method getimage in nsdata format. and then you can convert it into image from nsdata
.h File
//
// SignatureCaptureImageView.h
// TEST_DRAW_APP
//
1. List item
// Created by Talat Masud on 8/23/10.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#interface SignatureCaptureImageView : UIImageView {
CGPoint lastPoint;
BOOL mouseSwiped;
int mouseMoved;
}
-(NSData *)getImage;
#end
Implementation File
#import "SignatureCaptureImageView.h"
#implementation SignatureCaptureImageView
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Initialization code
self.userInteractionEnabled = YES;
mouseMoved = 0;
}
return self;
}
- (id)initWithImage:(UIImage*)image {
if ((self = [super initWithImage:image])) {
// Initialization code
self.userInteractionEnabled = YES;
mouseMoved = 0;
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwiped = NO;
UITouch *touch = [touches anyObject];
if ([touch tapCount] == 2)
{
//self.image = nil;
return;
}
lastPoint = [touch locationInView:self];
lastPoint.y -= 5;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
mouseSwiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self];
currentPoint.y -= 5;
UIGraphicsBeginImageContext(self.frame.size);
[self.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;
mouseMoved++;
if (mouseMoved == 10) {
mouseMoved = 0;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if ([touch tapCount] == 2) {
//self.image = nil;
return;
}
if(!mouseSwiped) {
UIGraphicsBeginImageContext(self.frame.size);
[self.image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
self.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
}
-(NSData *)getImage{
return UIImagePNGRepresentation(self.image);
}
- (void)dealloc {
[super dealloc];
}
#end
declare 2 UIImageViews , first with the image and second without any image, ie., empty UIImageView, but having an origin and size.
Then, when u want to animate, do the following,
[UIView animateWithDuration:3.0
animations:^{
CGRect sframe = mSecondImgView.frame;
mFirstImgView.frame = sframe;
}
completion:^(BOOL finished){
}];
I'm trying to implement a very simple drawing view in my app. This is only a small part of my app but it's turning into a real hassle. This is what I have so far, but all it's displaying right now is morse code like dots and lines.
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *savePath = [NSString stringWithFormat:#"%#/notePadImage.jpg",docsPath];
NSData *data = [NSData dataWithContentsOfFile:savePath];
UIImage *image = [UIImage imageWithData:data];
if (image == nil) {
NSString *pathToBlank = [[NSBundle mainBundle]pathForResource:#"blankNotePadPage" ofType:#"png"];
NSData *data = [NSData dataWithContentsOfFile:pathToBlank];
image = [UIImage imageWithData:data];
}
arrayOfTouches = [[NSMutableArray alloc] initWithCapacity:10];
self.drawImage.image = image;
mouseMoved = 0;
[self.view bringSubviewToFront:closeButton];
[self.view bringSubviewToFront:clearButton];
self.timer = [NSTimer scheduledTimerWithTimeInterval:.02 target:self selector:#selector(drawIt) userInfo:nil repeats:YES];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[arrayOfTouches addObject:touch];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[arrayOfTouches addObject:touch];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
}
-(void) drawIt {
NSMutableArray *tempArray = [NSMutableArray arrayWithArray:arrayOfTouches];
[arrayOfTouches removeAllObjects];
if ([tempArray count]>1) {
[arrayOfTouches removeAllObjects];
CGPoint point1 = [[tempArray objectAtIndex:0] previousLocationInView:self.view];;
CGPoint point2;
CGPoint point3;
for (int i = 0; i < [tempArray count]-1;i = i+1) {
UIGraphicsBeginImageContext(self.view.frame.size);
[drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 3.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 0.0, 1.0);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), point1.x, point1.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), point2.x, point2.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.view bringSubviewToFront:closeButton];
[self.view bringSubviewToFront:clearButton];
point1 = point2;
}
}
}
One of my apps also needed some simple drawing. Here is a slightly modified version of it. It works basically like hotpaw2 describes. I created a "canvas" view that handles all the drawing and I just add it wherever it's needed.
The speed is fine for my purposes.
CanvasView.h:
#interface CanvasView : UIView {
NSMutableArray *points;
}
#property (nonatomic, retain) NSMutableArray *points;
#end
CanvasView.m:
#import "CanvasView.h"
#implementation CanvasView
#synthesize points;
- (id) initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor blueColor];
}
return self;
}
-(void)drawRect:(CGRect)rect
{
if (self.points.count == 0)
return;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0); //white
CGContextSetLineWidth(context, 1.0);
CGPoint firstPoint = [[self.points objectAtIndex:0] CGPointValue];
CGContextBeginPath(context);
CGContextMoveToPoint(context, firstPoint.x, firstPoint.y);
int i = 1;
while (i < self.points.count)
{
CGPoint nextPoint = [[self.points objectAtIndex:i] CGPointValue];
if (nextPoint.x < 0 && nextPoint.y < 0)
{
CGContextDrawPath(context, kCGPathStroke);
if (i < (self.points.count-1))
{
CGContextBeginPath(context);
CGPoint nextPoint2 = [[self.points objectAtIndex:i+1] CGPointValue];
CGContextMoveToPoint(context, nextPoint2.x, nextPoint2.y);
i = i + 2;
}
else
i++;
}
else
{
CGContextAddLineToPoint(context, nextPoint.x, nextPoint.y);
i++;
}
}
CGContextDrawPath(context, kCGPathStroke);
}
-(void)dealloc
{
[points release];
[super dealloc];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event touchesForView:self] anyObject];
CGPoint location = [touch locationInView:self];
if (self.points == nil)
{
NSMutableArray *newPoints = [[NSMutableArray alloc] init];
self.points = newPoints;
[newPoints release];
}
[self.points addObject:[NSValue valueWithCGPoint:(location)]];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event touchesForView:self] anyObject];
CGPoint location = [touch locationInView:self];
[self.points addObject:[NSValue valueWithCGPoint:(location)]];
[self setNeedsDisplay];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event touchesForView:self] anyObject];
CGPoint location = [touch locationInView:self];
[self.points addObject:[NSValue valueWithCGPoint:(location)]];
CGPoint endPoint = CGPointMake(-99, -99); //"end of path" indicator
[self.points addObject:[NSValue valueWithCGPoint:(endPoint)]];
[self setNeedsDisplay];
}
#end
Adding the canvasView where it's needed:
CanvasView *cv = [[CanvasView alloc] initWithFrame:CGRectMake(0, 0, 320, 640)];
[self.view addSubview:cv];
[cv release];
Don't draw while handling touches. It will slow down the touch handler so much you might get the connect-the-dots-effect you are seeing.
Save the touch coordinates in an array and plan to draw them later.
Look at some simple animation tutorials for how to draw in a drawRect based on a setNeedsDisplay called by an animation UITimer or CADisplayLink. Draw all your line segments there at a more suitable rate.