Detecting number of touches - iphone

guys, I want to set actions to touches. If people make single touch - one action, else - different.
I've written this code in my touchesBegan method:
UITouch *touch = [event.allTouches anyObject];
BOOL tappedTwice = NO;
if ([touch tapCount] == 2) {
tappedTwice = YES;
NSLog(#"double touch");
}
else if ([touch tapCount] == 1 && !tappedTwice) {
NSLog(#"single touch");
}
But it's detecting single touch, and after it double, but it's incorrect in my situation. Have you any ideas?

Check this link. Just Configure number of tap required by setting
[tapGestureRecognizer setNumberOfTapsRequired:2];
and then handle this method
- (void)handleTap:(UITapGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateEnded) {
// handling code
}
}

Related

Identifying the Type of Touch Gestures from UIEvent Object

Is there a way to gain the type of touch gestures that triggered a UIEvent? So, let's say I intercept a gesture with hitTest:withEvent:. How do I identify what kind of touch (pinch, tap, swipe, etc.) happened that triggered this method?
I can gain the type of remote events from the UIEvent subtype, and even if the device was shaken, but there is no parameter for touch events...
How do you identify those?
You have to do touch analysis on your own.
It is not that difficult, but it is not done for you. Here a sample from some code I am actually using. It is not meant as a full-scale solution. It only detects basic tap/swipe/pinch gestures in a very concrete context (that of my app), and uses a rather uncool mechanism to deliver the gestures (notifications). So, it might apply to your case or more likely not, but I hope it gives you an idea of what is required.
NSSet* allTouches = [event allTouches];
UITouch* touch = [allTouches anyObject];
UIView* touchView = [touch view];
if (touch.phase == UITouchPhaseBegan) {
_initialView = touchView;
startTouchPosition1 = [touch locationInView:self];
startTouchTime = touch.timestamp;
if ([allTouches count] > 1) {
startTouchPosition2 = [[[allTouches allObjects] objectAtIndex:1] locationInView:self];
previousTouchPosition1 = startTouchPosition1;
previousTouchPosition2 = startTouchPosition2;
}
}
if (touch.phase == UITouchPhaseMoved) {
if ([allTouches count] > 1) {
CGPoint currentTouchPosition1 = [[[allTouches allObjects] objectAtIndex:0] locationInView:self];
CGPoint currentTouchPosition2 = [[[allTouches allObjects] objectAtIndex:1] locationInView:self];
CGFloat currentFingerDistance = CGPointDist(currentTouchPosition1, currentTouchPosition2);
CGFloat previousFingerDistance = CGPointDist(previousTouchPosition1, previousTouchPosition2);
if (fabs(currentFingerDistance - previousFingerDistance) > ZOOM_DRAG_MIN) {
NSNumber* movedDistance = [NSNumber numberWithFloat:currentFingerDistance - previousFingerDistance];
if (currentFingerDistance > previousFingerDistance) {
// NSLog(#"zoom in");
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_ZOOM_IN object:movedDistance];
} else {
// NSLog(#"zoom out");
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_ZOOM_OUT object:movedDistance];
}
}
}
}
if (touch.phase == UITouchPhaseEnded) {
CGPoint currentTouchPosition = [touch locationInView:self];
// Check if it's a swipe
if (fabsf(startTouchPosition1.x - currentTouchPosition.x) >= SWIPE_DRAG_HORIZ_MIN &&
fabsf(startTouchPosition1.x - currentTouchPosition.x) > fabsf(startTouchPosition1.y - currentTouchPosition.y) &&
touch.timestamp - startTouchTime < 0.7)
{
// It appears to be a swipe.
if (startTouchPosition1.x < currentTouchPosition.x) {
NSLog(#"swipe right");
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_SWIPE_RIGHT object:self];
} else {
NSLog(#"swipe left");
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_SWIPE_LEFT object:self];
}
} else {
//-- else, check if it's a single touch
if (touch.tapCount == 1) {
NSDictionary* uInfo = [NSDictionary dictionaryWithObject:touch forKey:#"touch"];
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_TAP object:self userInfo:uInfo];
}/* else if (touch.tapCount > 1) {
handle multi-touch
}
*/
}
startTouchPosition1 = CGPointMake(-1, -1);
_initialView = nil;
}
if (touch.phase == UITouchPhaseCancelled) {
_initialView = nil;
// NSLog(#"TOUCH CANCEL");
}
You need to analysis the touches(the count of touches and there position) yourself. Another easier way is to add corresponding gesture recognizer to get the corresponding type. All touch event's event type is UIEventSubtypeNone.
Since iOS 7 there's a delegate method that lets you know about URL interactions called textView(_:shouldInteractWith:in:interaction:).
https://developer.apple.com/documentation/uikit/uitextviewdelegate/1649337-textview

How to create various buttons which get called on simple touch

I have to make an app in which there are around 20 buttons, if I switch from one button to another button without removing the touch(i.e. by dragging the touch) I want to call the function when I entered in that button's frame region.
For example:when I drag touch from button's tag 10 to button's tag 11 then it should call button's tag 11 selector method.
I think you can not do it with UIButtons. But i have one suggestion for this may be it help you. Add Images instead of Buttons set those userIntractionEnable:NO then in touchesMoved method you can get call your #selector methods by comparing with X,Y co-ordinates.
I wrote a small code for this -
//I added your example image on my self.view with a view
//of 320x140 and set it userIntractionEnabled:NO
//Now in touchMoved: method did this..
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint pt = [touch locationInView:self.view];
//checking the touch is in self.view or not
if([touch view] == self.view)
{
//This is like a 2D array, So you have to follow row and column pattern.
if((pt.y>=0.0 && pt.y<=70.0))//For First Row
{
//These 7 are FirstRow Columns
if(pt.x>=0.0 && pt.x<=45.0){
NSLog(#"Method - 10");
}
if(pt.x>=46.0 && pt.x<=90.0){
NSLog(#"Method - 11");
}
if(pt.x>=91.0 && pt.x<=135.0){
NSLog(#"Method - 12");
}
if(pt.x>=136.0 && pt.x<=180.0){
NSLog(#"Method - 13");
}
if(pt.x>=181.0 && pt.x<=225.0){
NSLog(#"Method - 14");
}
if(pt.x>=226.0 && pt.x<=270.0){
NSLog(#"Method - 15");
}
if(pt.x>=271.0 && pt.x<=315.0){
NSLog(#"Method - 16");
}
}
//Row change this is for Second Row
if((pt.y>=71.0 && pt.y<=140.0))
{
//These 7 are SecondRow Columns
if(pt.x>=0.0 && pt.x<=45.0){
NSLog(#"Method - 17");
}
if(pt.x>=46.0 && pt.x<=90.0){
NSLog(#"Method - 18");
}
if(pt.x>=91.0 && pt.x<=135.0){
NSLog(#"Method - 19");
}
if(pt.x>=136.0 && pt.x<=180.0){
NSLog(#"Method - 20");
}
if(pt.x>=181.0 && pt.x<=225.0){
NSLog(#"Method - 21");
}
if(pt.x>=226.0 && pt.x<=270.0){
NSLog(#"Method - 22");
}
if(pt.x>=271.0 && pt.x<=315.0){
NSLog(#"Method - 23");
}
}
}
}
Hope this will help you !!!! :-)
You should register event with below way.
[button addTarget:self action:#selector(aMethod:) forControlEvents:UIControlEventTouchDragEnter];

start click in UIButton, but use touchesEnded in main view

I have, for example, a UIButton that I placed in IB.
This UIButton has two functions depending on whether it is just touched up inside or dragged outside - it would be nice to at least keep it functioning for touch up inside.
I want to click on my button and 'drag outside' but use -touchesEnded over a rectangle when I finally release my click.
I know that one option is to ditch the UIButton and use -touchesBegan over a mask, but that is a lot more effort and requires a nice big rewrite (considering the 96 buttons).
So to rephrase slightly - I've clicked on a button and held down the mouse, while dragging the cursor (/finger) over to a different point in my view and I want my view to recognise a -touchesEnded when I finally let go. The problem is that the initial click is tied up in the button so -touchesEnded in my main view doesn't happen...
Am i trying to do this the wrong way? Also, am I being clear?
EDIT: #Heckman has phrased the question well below
If I understand your question correctly, you are touching one button, that is contained within some UIView, and want to be able to drag your finger out, and recognize the point in the buttons superview.
Sounds to me like you should detect the button press from the button, then make a call to the [UIButton superview], to tell the superview about the button pressing that started, and then handle the touch end within the view.
To notify the superview of the button that was pressed call something like (from your UIButton):
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.superview buttonPressed:self]
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self.superview touchesEnded:touches withEvent:event];
}
In your superview code (if you have a property buttonPressed):
-(void) buttonPressed:(UIButton *) button {
_buttonPressed = button;
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if(self.buttonPressed) {
//Process the release from your drag here.
for(UITouch * touch in touches) {
//Use either of these to get the release position that you care about.
CGPoint releaseLocationInCurrentView = [touch locationInView:self];
CGPoint releaseLocationInButtonView = [touch locationInView:[self.buttonPressed]];
}
}
}
You might be able to use a UIPanGestureRecognizer on your UIView.
Here is some example code for how to implement gesture recognizers.
If you are looking for something like dragable items same as iphone homescreen icons then you can have a look to TTLauncherView sample from Three20 framework. http://three20.info/showcase/launcher
So, here's what I ended up doing, and it works quite nicely:
my UIButton on touchdragexit is assigned to an IBAction
-(IBAction)dragPoint:(id)sender {
//Do Something Useful in here - I assign the value to an Array that I can recall when I touch up inside one of 16 buttons
//Now pass the button touch on as a touch up outside
[myButton addTarget:self action:#selector(dragBegan:withEvent:) forControlEvents: UIControlEventTouchUpOutside];
}
so now I get my dragBegan like this:
- (void)dragBegan:(UIControl *)c withEvent:ev {
UITouch *touch = [[ev allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self.view]; // Get location of the moment I release the touch (touch up outside)
//now some long convoluted code to give me the location of a row of 16 buttons, of which I would like to know which one I touched up inside
UIButton *posButton;
int pos;
if(628.00<(touchPoint.y) && (touchPoint.y)<664.00){
if ((39.00<touchPoint.x && touchPoint.x<91.00) || (92.00<touchPoint.x && touchPoint.x<144.00) || (145.00<touchPoint.x && touchPoint.x<197.00) || (198.00<touchPoint.x && touchPoint.x<250.00)||(264.00<(touchPoint.x) && touchPoint.x<314.00)||(317.00<(touchPoint.x) && touchPoint.x<367.00)||(370.00<(touchPoint.x) && touchPoint.x<420.00)||(423.00<(touchPoint.x) && touchPoint.x<473.00)||(488.00<(touchPoint.x) && touchPoint.x<538.00) || (541.00<(touchPoint.x) && touchPoint.x<591.00) || (594.00<(touchPoint.x) && touchPoint.x<644.00) || (647.00<(touchPoint.x) && touchPoint.x<697.00)||(712.00<(touchPoint.x) && touchPoint.x<762.00)||(765.00<(touchPoint.x) && touchPoint.x<815.00)||(818.00<(touchPoint.x) && touchPoint.x<868.00)||(871.00<(touchPoint.x) && touchPoint.x<921.00)){
if(39.00<(touchPoint.x) && touchPoint.x<91.00){
posButton = SeqA;
pos=0;
}
else if(92.00<(touchPoint.x) && touchPoint.x<144.00){
posButton = SeqB;
pos=1;
}
else if(145.00<(touchPoint.x) && touchPoint.x<197.00){
posButton = SeqC;
pos=2;
}
else if(198.00<(touchPoint.x) && touchPoint.x<250.00){
posButton = SeqD;
pos=3;
}
else if(264.00<(touchPoint.x) && touchPoint.x<314.00){
posButton = SeqE;
pos=4;
}
else if(317.00<(touchPoint.x) && touchPoint.x<367.00){
posButton = SeqF;
pos=5;
}
else if(370.00<(touchPoint.x) && touchPoint.x<420.00){
posButton = SeqG;
pos=6;
}
else if(423.00<(touchPoint.x) && touchPoint.x<473.00){
posButton = SeqH;
pos=7;
}
else if(488.00<(touchPoint.x) && touchPoint.x<538.00){
posButton = SeqI;
pos=8;
}
else if(541.00<(touchPoint.x) && touchPoint.x<591.00){
posButton = SeqJ;
pos=9;
}
else if(594.00<(touchPoint.x) && touchPoint.x<644.00){
posButton = SeqK;
pos=10;
}
else if(647.00<(touchPoint.x) && touchPoint.x<697.00){
posButton = SeqL;
pos=11;
}
else if(712.00<(touchPoint.x) && touchPoint.x<762.00){
posButton = SeqM;
pos=12;
}
else if(765.00<(touchPoint.x) && touchPoint.x<815.00){
posButton = SeqN;
pos=13;
}
else if(818.00<(touchPoint.x) && touchPoint.x<868.00){
posButton = SeqO;
pos=14;
}
else if(871.00<(touchPoint.x) && touchPoint.x<921.00){
posButton = SeqP;
pos=15;
}
Now do something depending on the button you touched up inside
Other things I did - I created a mask of the original UIButton as a UIImageView that I made unhidden on a touchdragoutside event (and rebidden on the above touchupinside) so that I have a button I can drag

Detecting Single OR Double Tap

I'm trying to add 2 actions inside an IBAction, one for 1 tap and a different one for a double tap, and I came up with this code:
.h
UITouch * touch;
.m
- (IBAction) button {
BOOL tappedTwice = NO;
if ([touch tapCount] == 2) {
tappedTwice = YES;
// Action
}
else if ([touch tapCount] == 1 && !tappedTwice) {
// Action
} }
No errors, no warnings, but nothing happens when I tap the button... Any ideas???
You cannot capture events like that. The Action is tagged to touchUpInside event so you cannot capture single tap or double tap
Try this link
http://sree.cc/iphone/handling-touche-events-for-uibuttons-in-iphone

How to call a method only once during -(void)touchesMoved?

I am using - (void) touchesMoved to do stuff when ever I enter a specific frame, in this case the area of a button.
My problem is, I only want it to do stuff when I enter the frame - not when I am moving my finger inside the frame.
Does anyone know how I can call my methods only once while I am inside the frame, and still allow me to call it once again if I re-enter it in the same touchMove.
Thank you.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event touchesForView:self.view] anyObject];
CGPoint location = [touch locationInView:touch.view];
if(CGRectContainsPoint(p1.frame, location))
{
//I only want the below to me called
// once while I am inside this frame
[self pP01];
[p1 setHighlighted:YES];
}else {
[p1 setHighlighted:NO];
}
}
You can use some attribute to check if the code was already called when you were entering specific area. It looks like highlighted state of p1 object (not sure what it is) may be appropriate for that:
if(CGRectContainsPoint(p1.frame, location))
{
if (!p1.isHighlighted){ // We entered the area but have not run highlighting code yet
//I only want the below to me called
// once while I am inside this frame
[self pP01];
[p1 setHighlighted:YES];
}
}else { // We left the area - so we'll call highlighting code when we enter next time
[p1 setHighlighted:NO];
}
Simply add a BOOL that you check in touchesMoved and reset in touchesEnded
if( CGRectContainsPoint([p1 frame],[touch locationInView:self.view])) {
NSLog (#"Touch Moved over p1");
if (!p14.isHighlighted) {
[self action: p1];
p1.highlighted = YES;
}
}else {
p1.highlighted = NO;
}
try using a UIButton and use the 'touch drag enter' connection in Interface Builder.