how to get the touchesEnded location in longpress? - objective-c

In my application i have added gesture and these method
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleTap:)];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
UILongPressGestureRecognizer *longpress =[[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handellongpress:)];
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *start = [[event allTouches] anyObject];
CGPoint StartPoint = [start locationInView:self.view];
NSLog(#"start points x : %f y : %f", StartPoint.x, StartPoint.y);
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *move = [[event allTouches] anyObject];
CGPoint MovePoint = [move locationInView:self.view];
NSLog(#"MovePoint x : %f y : %f", MovePoint.x, MovePoint.y);
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *end = [[event allTouches] anyObject];
CGPoint EndPoint = [end locationInView:self.view];
NSLog(#"end ponts x : %f y : %f", EndPoint.x, EndPoint.y);
}
-(void)handellongpress:(UITapGestureRecognizer *)recognizer {
CGPoint LongTapPoint = [recognizer locationInView:self.view];
NSLog(#"LongTapPoint.x %f,LongTapPoint.y %f",LongTapPoint.x,LongTapPoint.y);
}
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
CGPoint SingleTap = [recognizer locationInView:self.view];
NSLog(#"SingleTap.x %f,SingleTap.y %f",SingleTap.x,SingleTap.y);
}
- (void)handleDoubleTap:(UITapGestureRecognizer *)recognizer {
CGPoint doubleTapPoint = [recognizer locationInView:self.view];
NSLog(#"doubleTapPoint.x %f,doubleTapPoint.y %f",doubleTapPoint.x,doubleTapPoint.y);
}
Now what i want is user touch down in a certain place, drag across to a new place, then hold in place for a while how to detect that last location. i m facing a problem in which if the user start there swipe from button location touchMove and touchEnd location method dint get called.
how to call touchEnd method in longpress.

if(gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
NSLog(#"UIGestureRecognizerStateBegan");
}
else if(gestureRecognizer.state == UIGestureRecognizerStateEnded)
{
NSLog(#"UIGestureRecognizerStateEnded");
}
else if(gestureRecognizer.state == UIGestureRecognizerStateChanged)
{
NSLog(#"UIGestureRecognizerStateChanged");
}
else if(gestureRecognizer.state == UIGestureRecognizerStateCancelled)
{
NSLog(#"UIGestureRecognizerStateCancelled");
}
else if(gestureRecognizer.state ==UIGestureRecognizerStateFailed )
{
NSLog(#"UIGestureRecognizerStateFailed");
}
use gestureRecogizer.state

Related

Implement touch cancel on UIButton

I have a subclassed UIButton that I made into an irregular shape (Parallelogram) where I override the touch events so it will only accept touch events inside the shape
How can I implement a touch event like a normal UIButton where I can cancel a touch event upon tapping and dragging the finger outside the UIButton to cancel a touch. For my current code, If I drag my finger inside the button, it calls the touchesCancelled event. I am using the TouchUpInside event for performing methods in the UIButton. Here is my code:
- (id)initWithFrame:(CGRect)frame withAngle:(AngleType)angle andColor:(UIColor *)color
{
if ((self = [super initWithFrame:frame])){
[self setImage:[Utils imageWithColor:color andSize:frame.size] forState:UIControlStateNormal];
_path = [UIBezierPath new];
self.angleType = angle;
switch (angle) {
case AngleLeft:
{
[_path moveToPoint:CGPointMake(0, elementHeight(self))];
[_path addLineToPoint:CGPointMake(elementWidth(self), elementHeight(self))];
[_path addLineToPoint:CGPointMake(elementWidth(self), 0)];
[_path addLineToPoint:CGPointMake(15, 0)];
[_path addLineToPoint:CGPointMake(0, elementHeight(self))];
}
break;
case AngleRight:
{
[_path moveToPoint:CGPointMake(0, 0)];
[_path addLineToPoint:CGPointMake(0, elementHeight(self))];
[_path addLineToPoint:CGPointMake(elementWidth(self),elementHeight(self))];
[_path addLineToPoint:CGPointMake(elementWidth(self) - 15, 0)];
[_path addLineToPoint:CGPointMake(0, 0)];
}
break;
case AngleBoth:
{
[_path moveToPoint:CGPointMake(15, 0)];
[_path addLineToPoint:CGPointMake(0, elementHeight(self))];
[_path addLineToPoint:CGPointMake(elementWidth(self) - 15, elementHeight(self))];
[_path addLineToPoint:CGPointMake(elementWidth(self), 0)];
[_path addLineToPoint:CGPointMake(15, 0)];
}
break;
default:
break;
}
CAShapeLayer *mask = [CAShapeLayer new];
mask.frame = self.bounds;
mask.path = _path.CGPath;
self.layer.mask = mask;
}
return self;
}
- (void)setText:(NSString *)text withAlignment:(NSTextAlignment)alignment
{
_buttonLabel = [[UILabel alloc] init];
_buttonLabel.font = FONT_Helvetica_Neue(14);
_buttonLabel.textColor = [UIColor whiteColor];
_buttonLabel.text = text;
_buttonLabel.textAlignment = alignment;
if (alignment == NSTextAlignmentLeft) {
_buttonLabel.frame = CGRectMake(15 + 10, 0, elementWidth(self), elementHeight(self));
} else if (alignment == NSTextAlignmentRight) {
_buttonLabel.frame = CGRectMake(0, 0, elementWidth(self) - 15 - 10, elementHeight(self));
} else if (alignment == NSTextAlignmentCenter) {
_buttonLabel.frame = CGRectMake(0, 0, elementWidth(self), elementHeight(self));
}
[self addSubview:_buttonLabel];
}
- (void)setBackgroundColor:(UIColor *)backgroundColor
{
[self setImage:[Utils imageWithColor:backgroundColor andSize:self.frame.size] forState:UIControlStateNormal];
CAShapeLayer *mask = [CAShapeLayer new];
mask.frame = self.bounds;
mask.path = _path.CGPath;
self.layer.mask = mask;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self];
if ([_path containsPoint:touchLocation]) {
NSLog(#"Inside!");
self.highlighted = YES;
//[self sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self];
self.highlighted = NO;
if ([_path containsPoint:touchLocation]) {
[self sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self];
if ([_path containsPoint:touchLocation]) {
NSLog(#"...");
self.highlighted = YES;
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self];
self.highlighted = NO;
if ([_path containsPoint:touchLocation]) {
[self sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
Instead of trying to implement custom touch events handling, please override the hitTest:withEvent: method. Please refer to this tutorial which I believe describes your case. And this is another example.

Drag multiple UIImageViews in an Array

This is what I have so far
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
for (UIImageView *imageView in _imageViewArray) {
CGPoint Location = [touch locationInView:touch.view];
imageView.center = Location;
}
}
The problem I am facing is when I move one image they all jump to the same place.
Thanks to cyberpawn this it what I did it get it to work
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint oldPoint = [touch previousLocationInView:touch.view];
CGPoint newPoint = [touch locationInView:touch.view];
CGPoint diff = CGPointMake(newPoint.x - oldPoint.x, newPoint.y - oldPoint.y);
for (UIImageView *imageView in _imageViewArray) {
if (CGRectContainsPoint(imageView.frame, newPoint)) {
CGPoint cntr = [imageView center];
[imageView setCenter:CGPointMake(cntr.x + diff.x, cntr.y + diff.y)];
}
}
}
Thats because you are moving them all to same location, you need to calculate the difference between touch locations and add that displacement to all views. Below code should solve your problem! Forget touchesBegan and Just override touchesMoved method like that.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint oldPoint = [touch previousLocationInView:touch.view];
CGPoint newPoint = [touch locationInView:touch.view];
CGPoint diff = CGPointMake(newPoint.x - oldPoint.x, newPoint.y - oldPoint.y);
for (UIImageView *imageView in _imageViewArray) {
CGPoint cntr = [imageView center];
[imageView setCenter:CGPointMake(cntr.x + diff.x, cntr.y + diff.y)];
}
}
If You want to move them separately when any of them is clicked than use below code instead!
float oldX, oldY;
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint pt = [touch locationInView:touch.view];
for (UIImageView *imageView in _imageViewArray) {
if(CGRectContainsPoint(imageView.frame, pt)) {
oldX = imageView.center.x - imageView.frame.origin.x - pt.x;
oldY = imageView.center.y - imageView.frame.origin.y - pt.y;
break;
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint pt = [touch locationInView:touch.view];
for (UIImageView *imageView in _imageViewArray) {
if (CGRectContainsPoint(imageView.frame, pt)) {
[self setCenter:CGPointMake(pt.x+oldX, pt.y+oldY)];
}
}
Enjoy Programming!
Here you coded like that only. If you want to move a single image, then you have to find that image and you should move that image alone.

Objective C: fix distance between images in touches moved

How could i set up my images(points) with same fix distance to new image(point) when performing a touches moved?
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:touch.view];
UIImageView *imageView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Crayon_Black.png"]];
imageView.center = touchLocation;
[drawImage addSubview:imageView];
}
I hope this make sense. I just need to finish my school project. Thanks guys in advance.
This solution works as long as you don't move finger too fast:
#interface ViewController : UIViewController {
CGPoint lastLocation_;
CGFloat accumulatedDistance_;
}
...
-(CGFloat) distanceFromPoint:(CGPoint)p1 ToPoint:(CGPoint)p2 {
CGFloat xDist = (p2.x - p1.x);
CGFloat yDist = (p2.y - p1.y);
return sqrt((xDist * xDist) + (yDist * yDist));
}
-(void) addImageAtLocation:(CGPoint)location {
UIImageView *imageView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Crayon_Black.png"]];
imageView.center = location;
[self.view addSubview:imageView];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
lastLocation_ = [[touches anyObject] locationInView:self.view];
accumulatedDistance_ = 0;
[self addImageAtLocation:lastLocation_];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
CGFloat distance = [self distanceFromPoint:touchLocation ToPoint:lastLocation_];
accumulatedDistance_ += distance;
CGFloat fixedDistance = 40;
if (accumulatedDistance_ > fixedDistance) {
[self addImageAtLocation:touchLocation];
while (accumulatedDistance_ > fixedDistance) {
accumulatedDistance_ -= fixedDistance;
}
}
lastLocation_ = touchLocation;
}

Differentiate between two ImageViews

I have two imageViews imageView1 and imageView2. I have given gestureRecognizer to move these both images. Now the problem is when i move first imageView near second imageView only second image view is displayed. But when i put first imageView on another image the first imageView should be displayed on the second imageView which is not happening.Can any body please tell me how can the first imageView gets view on the top of another imageView.
You can use the UIView method bringSubviewToFront:, and pass in the UIImageView that you want displayed on top.
Why dont you use something similar like this to drag your UIImageViews?
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor yellowColor];
test1 = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
test1.backgroundColor = [UIColor whiteColor];
test1.userInteractionEnabled = YES;
test1.clipToBounds = YES;
[self.view addSubview:test1];
test2 = [[UIImageView alloc] initWithFrame:CGRectMake(400, 400, 100, 100)];
test2.backgroundColor = [UIColor whiteColor];
test2.userInteractionEnabled = YES;
test2.clipToBounds = YES;
[self.view addSubview:test2];
}
CGPoint startLocation;
float diffX;
float diffY;
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
if( [touch view] == test1)
{
startLocation = [touch locationInView:self.view];
[self.view bringSubviewToFront:test1];
}
if( [touch view] == test2)
{
startLocation = [touch locationInView:self.view];
[self.view bringSubviewToFront:test2];
}
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
if( [touch view] == test1)
{
CGPoint location = [touch locationInView:self.view];
diffX = location.x - startLocation.x;
diffY = location.y - startLocation.y;
test1.frame = CGRectMake(test1.frame.origin.x + diffX, test1.frame.origin.y + diffY, test1.frame.size.width, test1.frame.size.height);
startLocation = test1.frame.origin;
}
if( [touch view] == test2)
{
CGPoint location = [touch locationInView:self.view];
diffX = location.x - startLocation.x;
diffY = location.y - startLocation.y;
test2.frame = CGRectMake(test2.frame.origin.x + diffX, test2.frame.origin.y + diffY, test2.frame.size.width, test2.frame.size.height);
startLocation = test2.frame.origin;
}
}
//---EDIT---//
Added: cliptobounds in viewdidload

How to drag only one image with iPhone SDK

I want to create a little app that takes two images and i want to make only the image over draggable.
After research, i found this solution:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[ event allTouches] anyObject];
image.alpha = 0.7;
if([touch view] == image){
CGPoint location = [touch locationInView:self.view];
image.center = location;
}
It works but the problem is that the image is draggable from its center and I don't want that.
So I found another solution:
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
// Retrieve the touch point
CGPoint pt = [[touches anyObject] locationInView:self.view];
startLocation = pt;
[[self view] bringSubviewToFront:self.view];
}
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
// Move relative to the original touch point
CGPoint pt = [[touches anyObject] locationInView:self.view];
frame = [self.view frame];
frame.origin.x += pt.x - startLocation.x;
frame.origin.y += pt.y - startLocation.y;
[self.view setFrame:frame];
}
It works very well but when I add another image, all the images of the view are draggable at the same time. I'm a beginner with the iPhone development and I have no idea of how I can only make the image over draggable.
You can use if condition in the touchesBegan: method, See this-
-(void)ViewDidLoad
{
//Your First Image View
UIImageView *imageView1 = [UIImageView alloc]initWithFrame:CGRectMake(150.0, 100.0, 30.0, 30.0)];
[imageView1 setImage:[UIImage imageNamed:#"anyImage.png"]];
[imageView1 setUserInteractionEnabled:YES];
[self.view addSubview:imageView1];
//Your Second Image View
UIImageView *imageView2 = [UIImageView alloc]initWithFrame:CGRectMake(150.0, 200.0, 30.0, 30.0)];
[imageView2 setImage:[UIImage imageNamed:#"anyImage.png"]];
[imageView2 setUserInteractionEnabled:YES];
[self.view addSubview:imageView2];
}
//Now Use Touch begin methods with condition like this
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches]anyObject];
if([touch view] == imageView1)
{
CGPoint pt = [[touches anyObject] locationInView:imageView1];
startLocation = pt;
}
if([touch view] == imageView2)
{
CGPoint pt = [[touches anyObject] locationInView:imageView2];
startLocation = pt;
}
}
//Use same thing with touch move methods...
- (void) touchesMoved:(NSSet *)touches withEvent: (UIEvent *)event
{
UITouch *touch = [[event allTouches]anyObject];
if([touch view] == imageView1)
{
CGPoint pt = [[touches anyObject] previousLocationInView:imageView1];
CGFloat dx = pt.x - startLocation.x;
CGFloat dy = pt.y - startLocation.y;
CGPoint newCenter = CGPointMake(imageView1.center.x + dx, imageView1.center.y + dy);
imageView1.center = newCenter;
}
if([touch view] == imageView2)
{
CGPoint pt = [[touches anyObject] previousLocationInView:imageView2];
CGFloat dx = pt.x - startLocation.x;
CGFloat dy = pt.y - startLocation.y;
CGPoint newCenter = CGPointMake(imageView2.center.x + dx, imageView2.center.y + dy);
imageView2.center = newCenter;
}
}
These two images will move only when you touch on it and move it. I hope my tutorials will help you.
Simply use these two methods
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
myImage.center = location;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesBegan:touches withEvent:event];
}
Let's break it down. You should have a main containerView (object of UIView) in your view controller. Within that, you should have DragableImageView objects.
DragableImageView inherits UIImageView and within that, you add your touches code. (Right now you are doing self.frame = position which is wrong - and obviously it will move all images at once - because if I understand correctly, you are adding these touches in your view controller).
Create only DragableImageView first, test it. Then add two DragableImageView instances. test them in different configurations.. you might want to hit test in the containerView to see which DragableImageView should be dragged (e.g. if you have jigsaw pieces, you might want to pick the one that is at the back rather than the front one).