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.
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];
}
I have the following codes to draw lines in a UIView. But once I start drawing, the view becomes dark grey. How can I make the background transparent? I already set the backgroundColor to clearColor, but the background is still dark gray. What did I miss?
#interface CanvasView () {
UIColor *colorLine;
UIBezierPath *pathBezier;
}
#end
#implementation CanvasView
#synthesize imgCached;
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if(self) {
self.backgroundColor = [UIColor clearColor];
[self setMultipleTouchEnabled:NO];
pathBezier = [[UIBezierPath alloc] init];
pathBezier.lineWidth = 5;
colorLine = [UIColor redColor];
}
return self;
}
- (void)drawRect:(CGRect)rect {
[self.imgCached drawInRect:rect];
[pathBezier stroke];
}
- (void)drawCache {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0.0);
[colorLine setStroke];
if(!self.imgCached) {
UIBezierPath *rectpath = [UIBezierPath bezierPathWithRect:self.bounds];
[rectpath fill];
}
[self.imgCached drawAtPoint:CGPointZero];
[pathBezier stroke];
self.imgCached = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
- (void)clearGraphics {
self.imgCached = nil;
[pathBezier removeAllPoints];
[self setNeedsDisplay];
}
#pragma mark - Touch methods
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[touches allObjects] objectAtIndex:0];
[pathBezier moveToPoint:[touch locationInView:self]];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[touches allObjects] objectAtIndex:0];
[pathBezier addLineToPoint:[touch locationInView:self]];
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[pathBezier addLineToPoint:p];
[self drawCache];
[self setNeedsDisplay];
[pathBezier removeAllPoints];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[self touchesEnded:touches withEvent:event];
}
p.s. the imgCached is:
#property (nonatomic, strong) UIImage *imgCached;
Replace your drawRect: and drawCache methods with the following:
- (void)drawRect:(CGRect)rect {
[self.imgCached drawInRect:rect];
[colorLine setStroke];
[pathBezier stroke];
}
- (void)drawCache {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
[colorLine setStroke];
[self.imgCached drawAtPoint:CGPointZero];
[pathBezier stroke];
self.imgCached = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
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;
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.
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