CGContext strangeness - ios

I have a little code module that should refer as signature panel so that the user can sign on this panel with his finger. The whole thing runs on the iPad.
Now, I managed to do the usual touchesBegan(), touchesMoved(), touchesEnded() carousel to make him sign on that panel. While signing, I draw his signature on the main view. However, due to whatever reason, the image appears twice: once correctly and once upside down above the main signature (see image). Since I don't see any translating being done in my code, I suspect that the whole code might be incorrect, but I don't know why. Does anyone know what I'm doing wrong here?
#import "RMSignatureView.h"
#import <QuartzCore/QuartzCore.h>
#interface RMSignatureView() {
CGPoint origin;
}
-(void) setupLayer;
#property (nonatomic, retain) UIImage* image;
#end
#implementation RMSignatureView
#synthesize image;
-(void) dealloc {
[image release];
[super dealloc];
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setupLayer];
}
return self;
}
-(id) initWithCoder:(NSCoder *)aDecoder {
if ([super initWithCoder:aDecoder] == self) {
[self setupLayer];
}
return self;
}
-(void) setupLayer {
self.layer.cornerRadius = 10;
self.layer.borderColor = [UIColor colorWithRed:109.0/256.0 green:149.0/256.0 blue:224.0/256.0 alpha:1.0].CGColor;
self.layer.borderWidth = 0.5f;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetStrokeColorWithColor(context, [UIColor grayColor].CGColor);
CGFloat sizes[2];
sizes[0] = 1;
sizes[1] = 1;
CGContextSetLineDash(context, 0, sizes, 2);
CGContextMoveToPoint(context, rect.origin.x + 50, rect.origin.y + rect.size.height - 30);
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width - 50, rect.origin.y + rect.size.height - 30);
CGContextStrokePath(context);
CGContextSetLineDash(context, 0, NULL, 0);
if (image)
CGContextDrawImage(context, rect, image.CGImage);
CGContextRestoreGState(context);
}
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];
origin = [touch locationInView:self];
}
-(void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
origin.x = -1;
origin.y = -1;
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
origin.x = -1;
origin.y = -1;
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];
if (origin.x != -1 && origin.y != -1) {
UIGraphicsBeginImageContext(self.frame.size);
#try {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
if (image)
CGContextDrawImage(context, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), image.CGImage);
CGContextMoveToPoint(context, origin.x, origin.y);
origin = [touch locationInView:self];
CGContextAddLineToPoint(context, origin.x, origin.y);
CGContextStrokePath(context);
self.image = UIGraphicsGetImageFromCurrentImageContext();
CGContextRestoreGState(context);
}
#finally {
UIGraphicsEndImageContext();
}
}
[self setNeedsDisplay];
}
#end

Found it.. Quartz has (0, 0) in the lower left instead of upper left.

Related

Creating an ios paint application

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];
}

How will i remove UIBezierPath from the uiview on button click.?

I am working on digital signature on uiview. i create it normaly by this code, but i am not able to remove bezier path on button click.i am sharing my code PLease look at my code.
#import "Signature.h"
#implementation Signature {
UIBezierPath *path;
UIImage *incrementalImage;
CGPoint pts[5]; // we now need to keep track of the four points of a Bezier segment and the first control point of the next segment
uint ctr;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder])
{
[self setMultipleTouchEnabled:NO];
[self setBackgroundColor:[UIColor greenColor]];
path = [UIBezierPath bezierPath];
[path setLineWidth:2.0];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setMultipleTouchEnabled:NO];
path = [UIBezierPath bezierPath];
[path setLineWidth:2.0];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
[incrementalImage drawInRect:rect];
[path stroke];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
ctr = 0;
UITouch *touch = [touches anyObject];
pts[0] = [touch locationInView:self];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
ctr++;
pts[ctr] = p;
if (ctr == 4)
{
pts[3] = CGPointMake((pts[2].x + pts[4].x)/2.0, (pts[2].y + pts[4].y)/2.0); // move the endpoint to the middle of the line joining the second control point of the first Bezier segment and the first control point of the second Bezier segment
[path moveToPoint:pts[0]];
[path addCurveToPoint:pts[3] controlPoint1:pts[1] controlPoint2:pts[2]]; // add a cubic Bezier from pt[0] to pt[3], with control points pt[1] and pt[2]
[self setNeedsDisplay];
// replace points and get ready to handle the next segment
pts[0] = pts[3];
pts[1] = pts[4];
ctr = 1;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self drawBitmap];
[self setNeedsDisplay];
[path removeAllPoints];
ctr = 0;
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"hello");
[self touchesEnded:touches withEvent:event];
}
- (void)drawBitmap
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0.0);
if (!incrementalImage) // first time; paint background white
{
UIBezierPath *rectpath = [UIBezierPath bezierPathWithRect:self.bounds];
[[UIColor greenColor] setFill];
[rectpath fill];
}
[incrementalImage drawAtPoint:CGPointZero];
[[UIColor blackColor] setStroke];
[path stroke];
incrementalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
- (void)erase {
NSLog(#"Erase Testing...");
// self->path = nil; //Set current path nil
//path = [UIBezierPath bezierPath];
// [self setNeedsDisplay];
}
I call erase method on unbutton click from another class, but I am not able to remove uibezeripath.
Try using this to remove the UIBezierPath,
[path removeAllPoints];
If you use CAShapeLayer *rectLayer = [[CAShapeLayer alloc] init]; aswell then call this line too,
[rectLayer removeFromSuperlayer];
Check how i am using this in one of my project if it can help,
- (void)drawRect:(CGRect)rect {
[_path stroke];
}
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame: frame];
if (self) {
// set Multiple touches Enabled to false for allow only single touch.
[self setMultipleTouchEnabled: NO];
_path = [UIBezierPath bezierPath];
// set Line width.
[_path setLineWidth:2.0];
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
isMouseswipped = NO; //for touches eneded to make dot
ctr = 0;
UITouch *myTouch = [touches anyObject];
pts[0] = [myTouch locationInView: self];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
isMouseswipped = YES; //for touches eneded to make dot
CustomSignatureViewController *csvc = [[CustomSignatureViewController alloc]init];
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView: self];
ctr++;
pts[ctr] = p;
if (ctr == 4) {
pts[3] = CGPointMake((pts[2].x + pts[4].x)/2.0, (pts[2].y + pts[4].y)/2.0);
[_path moveToPoint: pts[0]];
[_path addCurveToPoint: pts[3] controlPoint1:pts[1] controlPoint2:pts[2]];
[self setNeedsDisplay];
pts[0] = pts[3];
pts[1] = pts[4];
ctr = 1;
csvc.status = 1;
self.status = 1;
}
}
- (void)erase {
_path = nil;
_path = [UIBezierPath bezierPath];
[_path setLineWidth:2.0];
[self setNeedsDisplay];
}
This is custom class which returns uiview to fraw signature. It is subclass of UIView.
So when required signature, i import this class and instantiate it and got uiview object on which i can draw. then capture that view as image using graphics beginimage context!
Update :
In viewcontroller i am calling method like,
-(void)clear : (id)sender{
[signView erase];
signView.status = 0;
}
signView is signature class(as mentioned above)'s object. and erase is public method declared in .h file of signature class. (note : signature class is subclass of uiview so intance of it returns view onject so signView is uiview object)
Hope this will help :)
use this code it will help you
- (void)resetPath {
path = nil;
path = [UIBezierPath bezierPath];
[self setNeedsDisplay];
}
create this method in .h file of your subclass. From your UIViewController class you call this method whenever you need it
- (IBAction)youraction:(id)sender
{
[self.subclassedView resetPath];
}

eraser tool for vector drawings ios

I'm implementing my draw tools like this:
CGPoint CGPointCropByRect1(CGPoint point, CGRect rect)
{
rect = CGRectInset(rect, 5., 5.);
return CGPointMake(MIN(CGRectGetMaxX(rect), MAX(CGRectGetMinX(rect), point.x)), MIN(CGRectGetMaxY(rect), MAX(CGRectGetMinY(rect), point.y)));
}
CGFloat CGPointLengthToPoint1(CGPoint first, CGPoint second)
{
return sqrtf(powf(second.x - first.x, 2.) + powf(second.y - first.y, 2.));
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
_paths = [[NSMutableArray alloc] init];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
UIColor *color = [UIColor blackColor];
CGFloat width = 5.f;
if (_isErase) {
CGContextSetStrokeColorWithColor(ctx, [UIColor clearColor].CGColor);
//CGContextSetFillColorWithColor(ctx, [UIColor clearColor].CGColor);
CGContextSetBlendMode(ctx, kCGBlendModeClear);
}
else {
CGContextSetStrokeColorWithColor(ctx, [color CGColor]);
CGContextSetLineWidth(ctx, width);
CGContextSetLineJoin(ctx, kCGLineJoinRound);
CGContextSetLineCap(ctx, kCGLineCapRound);
}
for(NSArray *array in _paths)
{
size_t index = 0;
CGPoint first = [[array objectAtIndex:index++] CGPointValue];
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, first.x, first.y);
while (index < array.count)
{
CGPoint middlePoint = [[array objectAtIndex:index++] CGPointValue];
if(index < array.count)
{
CGPoint endPoint = [[array objectAtIndex:index++] CGPointValue];
//CGContextAddQuadCurveToPoint(ctx, middlePoint.x, middlePoint.y, endPoint.x, endPoint.y);
CGContextAddLineToPoint(ctx, middlePoint.x, middlePoint.y);
CGContextAddLineToPoint(ctx, endPoint.x, endPoint.y);
}
else
CGContextAddLineToPoint(ctx, middlePoint.x, middlePoint.y);
}
CGContextStrokePath(ctx);
}
CGContextBeginPath(ctx);
BOOL first = YES;
for(NSValue *point in _currentPath)
{
if(first)
CGContextMoveToPoint(ctx, point.CGPointValue.x, point.CGPointValue.y);
else
CGContextAddLineToPoint(ctx, point.CGPointValue.x, point.CGPointValue.y);
first = NO;
}
CGContextStrokePath(ctx);
CGContextRestoreGState(ctx);
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
_currentPath = [[NSMutableArray alloc] init];
[_currentPath addObject:[NSValue valueWithCGPoint:[[touches anyObject] locationInView:self]]];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint currentTouch = [[touches anyObject] locationInView:self];
if(!CGRectContainsPoint(self.bounds, currentTouch))
{
if(!_currentPath.count)
return;
currentTouch = CGPointCropByRect1(currentTouch, self.bounds);
CGPoint lastTouch = [[_currentPath objectAtIndex:_currentPath.count - 1] CGPointValue];
[_currentPath addObject:[NSValue valueWithCGPoint:currentTouch]];
[self setNeedsDisplayInRect:CGRectInset(CGRectMake(currentTouch.x, currentTouch.y, lastTouch.x - currentTouch.x, lastTouch.y - currentTouch.y), -10., -10.)];
return;
}
if(_currentPath.count == 0)
{
_currentPath = [[NSMutableArray alloc] init];
[_currentPath addObject:[NSValue valueWithCGPoint:currentTouch]];
return;
}
CGPoint lastTouch = [[_currentPath objectAtIndex:_currentPath.count - 1] CGPointValue];
CGFloat dim = CGPointLengthToPoint1(currentTouch, lastTouch);
if(dim > 5.)
{
[_currentPath addObject:[NSValue valueWithCGPoint:currentTouch]];
[self setNeedsDisplayInRect:CGRectInset(CGRectMake(currentTouch.x, currentTouch.y, lastTouch.x - currentTouch.x, lastTouch.y - currentTouch.y), -10., -10.)];
}
}
-(void)dropPath
{
if(_currentPath.count)
[_paths addObject:[NSArray arrayWithArray:_currentPath]];
[_currentPath release];
_currentPath = nil;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint currentTouch = [[touches anyObject] locationInView:self];
if (!_isErase) {
//CGPoint currentTouch = [[touches anyObject] locationInView:self];
[_currentPath addObject:[NSValue valueWithCGPoint:currentTouch]];
[self dropPath];
[self setNeedsDisplay];
}
else{
[_currentPath removeObject:[NSValue valueWithCGPoint:currentTouch]];
[self dropPath];
[self setNeedsDisplay];
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
}
#end
the main idea is- I'm storing my current points in NSArray, and then add it in another array.
How can I create a eraser? I think the main idea is to redraw the lines, but how to implement it? Is there any of examples that will make it clear for me?
The option for using background color doesn't fit.
Thanks
You can try adding this snipper:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddPath(context, self.path);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.lineWidth);
CGContextSetStrokeColorWithColor(context, [UIColor clear].CGColor);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextSetAlpha(context, self.lineAlpha);
CGContextStrokePath(context);

Calligraphy Drawing IOS Coregraphics

I am looking to have something which is marked in red, as marker but don't know whether it can be done or not.
It looks like marking using a calligraphy pen.
Trying out the following code as answered by "Andrey", I get the following output with spaces while drawing.
Brush image can be found here used is
Making further changes to the code, I found still I am not able to get the expected result.
Here I am trying to fill the path which exists between the current point and the next point.
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGFloat w=5.0;
CGFloat h=2.0;
CGContextRef context=UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
for(int i=0;i<self.positions.count;i++){
CGPoint point=[[self.positions objectAtIndex:i] CGPointValue];
CGFloat x=point.x-(w/2.0);
CGFloat y=point.y-(h/2.0);
CGContextFillRect(context, CGRectMake(x, y, w, h));
if(i+1<self.positions.count){
CGPoint nextPoint=[[self.positions objectAtIndex:(i+1)] CGPointValue];
CGMutablePathRef myPath=CGPathCreateMutable();
CGPathMoveToPoint(myPath, NULL, x, y);
CGFloat x1=nextPoint.x-(w/2.0);
CGFloat y1=nextPoint.y-(h/2.0);
CGPathAddLineToPoint(myPath, NULL, x1, y1);
CGPathAddLineToPoint(myPath, NULL, w, y1);
CGPathAddLineToPoint(myPath, NULL, w, y);
CGPathCloseSubpath(myPath);
CGContextFillPath(context);
}
}
}
Those picture can be done via drawing an image in UIView subclass with overridden drawRect: message. You also need to add some kind of touch handler for catching touches. So here is some code:
#interface DrawingView ()
#property (nonatomic, strong) NSMutableArray *positions;
#end
#implementation DrawingView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self awakeFromNib];
}
return self;
}
- (void)awakeFromNib
{
self.positions = [[NSMutableArray alloc] init];
}
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
UIImage *brushImage = [UIImage imageNamed:#"brush.png"];
for (NSValue *object in self.positions) {
CGPoint point = [object CGPointValue];
[brushImage drawAtPoint:CGPointMake(point.x - brushImage.size.width / 2.0, point.y - brushImage.size.height / 2.0)];
}
}
- (void)addPoint:(CGPoint)point
{
[self.positions addObject:[NSValue valueWithCGPoint:point]];
[self setNeedsDisplay];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
[self addPoint:[touch locationInView:self]];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
[self addPoint:[touch locationInView:self]];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
[self addPoint:[touch locationInView:self]];
}
#end
You only need to create a proper brush.png and place those view anywhere you want.

How to draw dashed line with finger in iPhone app?

I need to draw a line with dashes at regular gaps by sliding finger on the iPhone screen. I have written the following code for that and it is drawing the dashed line but the gaps are not regular and thus it is not looking good. I have also provided a link to the video showing the issue Please help!
Link to video:
https://dl.dropbox.com/u/56721867/Screen%20Recording%207.mov
CGPoint mid1 = midPoint__5(previousPoint1, previousPoint2);
CGPoint mid2 = midPoint__5(currentPoint, previousPoint1);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.layer renderInContext:context];
self.lineColor=[arrObj objectAtIndex:colorTag];
CGContextMoveToPoint(context, mid1.x, mid1.y);
CGContextAddQuadCurveToPoint(context, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y);
CGContextSetLineCap(context, kCGLineCapRound);//use for making circle ,rect or line effect===============
CGFloat dashArray[] = {2,8,2,8};
CGContextSetLineDash(context,2,dashArray, 4);
CGContextSetLineWidth(context, self.lineWidth);
self.lineColor=[arrObj objectAtIndex:[AppHelper userDefaultsForKey:#"ColorTag"].intValue];//color tag on button click
CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
CGContextSetAlpha(context, 1.0);
CGBlendMode blendStyle=isErase?kCGBlendModeClear:kCGBlendModeNormal;
CGContextSetBlendMode(context,blendStyle);
CGContextStrokePath(context);
[super drawRect:rect];
It's rather unclear from the code, but based on the video and a hunch I'd guess a single swipe with the finger ends up as several line segments. This means that the dashing starts from scratch several times, creating the effect in the video. You probably need a NSMutableArray where you put all those currentPoint into, and then draw them all as one line every time you redraw.
This question has more information on how to draw lines in this way: iPhone Core Graphics thicker dashed line for subview
Here is the code to do what you are trying, it uses Quartz instead of CoreGraphics. You can use either Quartz or CoreGraphics.
//
// TestView.h
//
//
// Created by Syed Arsalan Pervez on 2/18/13.
// Copyright (c) 2013 SAPLogix. All rights reserved.
//
#import <UIKit/UIKit.h>
#interface TestView : UIView
{
NSMutableArray *_points;
}
#end
//
// TestView.m
//
//
// Created by Syed Arsalan Pervez on 2/18/13.
// Copyright (c) 2013 SAPLogix. All rights reserved.
//
#import "TestView.h"
#interface UserPoint : NSObject
{
BOOL _start;
BOOL _end;
CGPoint _point;
}
#property (assign, nonatomic) BOOL start;
#property (assign, nonatomic) BOOL end;
#property (assign, nonatomic) CGPoint point;
#end
#implementation UserPoint
#end
#implementation TestView
- (id)init
{
self = [super init];
if (self)
{
_points = [NSMutableArray new];
}
return self;
}
- (UserPoint *)addPoint:(CGPoint)point
{
UserPoint *_userPoint = [UserPoint new];
_userPoint.point = point;
[_points addObject:_userPoint];
[_userPoint release];
return [_points lastObject];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
UserPoint *_userPoint = [self addPoint:[touch locationInView:self]];
_userPoint.start = YES;
_userPoint = nil;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
UserPoint *_userPoint = [self addPoint:[touch locationInView:self]];
_userPoint = nil;
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
UserPoint *_userPoint = [self addPoint:[touch locationInView:self]];
_userPoint.end = YES;
_userPoint = nil;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
[[UIColor blackColor] setStroke];
[[UIColor blackColor] setFill];
UIBezierPath *path = [UIBezierPath bezierPath];
[path setLineWidth:15];
CGFloat dash[] = {15,20};
[path setLineDash:dash count:2 phase:0];
[path setLineCapStyle:kCGLineCapRound];
CGPoint lastPoint;
for (UserPoint *_point in _points)
{
if (_point.start || _point.end)
[path moveToPoint:_point.point];
else
{
[path addQuadCurveToPoint:_point.point controlPoint:lastPoint];
}
lastPoint = _point.point;
}
[path stroke];
}
- (void)dealloc
{
[_points release];
[super dealloc];
}
#end

Resources