If a notification(i.e., a UIAlertView) appears while touching the screen (or home button is being pressed), ccTouchEnded will be called in game layer, but at the touch will already have ended.
How can I determine when the touch ends?
Check out the apple reference for UIResponder:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIResponder_Class/Reference/Reference.html
You probably want
touchesEnded:withEvent:
Hope this helps :)
You should implement ccTouchesCancelled. This will occur whenever a touch event is interrupted.
Just check how many touch objects you have.
if([touches count] == 0)
{
//NO TOUCHES
}
-Make your scene conforms to protocol CCTargetedTouchDelegate
-Add This line to init of your scene:
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:NO];
-Implement these functions:
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
return YES;
}
-(void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
//here touch is ended
}
Related
I am trying to create a custom gesture recogniser for my view. I am following this answer mentioned in here: But for some reason the touched Ended and also touches movied are not getting called. Only touches began get called.
SubClass:
#import "TapGesture.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
#implementation TapGesture
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
if (self.state == UIGestureRecognizerStatePossible) {
self.state = UIGestureRecognizerStateRecognized;
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
self.state = UIGestureRecognizerStateFailed;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
self.state = UIGestureRecognizerStateFailed;
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
}
#end
and I am initialising the TapGesture as follows:
TapGesture *tapGesture=[[TapGesture alloc]initWithTarget:self action:#selector(incrementValue)];
tapGesture.delaysTouchesEnded=NO;
tapGesture.cancelsTouchesInView=NO;
[_workButton addGestureRecognizer:tapGesture]; //_workButton is a UIView
I don;t have any other gesture recognisers in the view. If I use the same methods in the UIView, all of them are called as expected.
Why the touchesEnded/touchesMoved are not getting called when overrride in UIGestureRecogniser class ?
When subclassing UIGestureRecognizer you must make it act like a continuous gesture and handle it's state machine by yourself (i.e., manually set it's state).
From the iOS Developer Library Docs on UIGestureRecognizer:
Subclasses must set the state property to the appropriate value when they transition between states.
See here for more info (Scroll down to Subclasing Notes)
Note: to make state read/write and not read-only, you should use UIGestureRecognizerSubclass.h as also noted on the docs:
The state property is declared in UIGestureRecognizer.h as being read-only. This property declaration is intended for clients of gesture recognizers. Subclasses of UIGestureRecognizer must import UIGestureRecognizerSubclass.h. This header file contains a redeclaration of state that makes it read-write.
I found that this is required for a double tap gesture but not for a single tap gesture:
doubleTapGestureRecognizer.delaysTouchesEnded = NO;
I have a segmented control,with 5 segments..I want some event to be fired when a touch down happens on any of the segment and i mean tap and hold,without lifting the finger.
And when the user lifts his finger,it should reset
I have tried using touchesBegan and touchesEnded but i don't get the current selectedIndex in touchesBegan,here's my code
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
long oldValue = self.selectedSegmentIndex;
[super touchesBegan:touches withEvent:event];
if (oldValue == self.selectedSegmentIndex )
[self sendActionsForControlEvents:UIControlEventValueChanged];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"touchesEnded");
NSLog(#"selectedIndex%lu",self.selectedSegmentIndex);
[super touchesEnded:touches withEvent:event];
self.selectedSegmentIndex = -1;
}
Is there any way to achieve a touch down event effect for a segmentedControl,or any other alternative?
You can use touchDown: IBAction selector.
You can try to override:
- (void) setSelectedSegmentIndex:(NSInteger)toValue
Quite frankly, I do not think it is possible to do with UISegmentedControl. You do not get selected segment index until touchesEnded:withEvent: is called.
If you want to get in touchesBegan:withEvent:, my advise would be to write your own custom view that look like UISegmentedControl and gives you call back on touchesBegan:withEvent:.
As suggested by kientux above, adding transparent views or buttons on top of each segment in UISegmentedControl could be another potential solution to your problem but it would be very very tricky!
Good luck!
I am making a custom iOS keyboard and have a UIControl subclass to represent my button. I am trying to get the same behaviour as the normal iOS keyboard:
User begins touch on one button
User drags over other buttons (need to detect this so they can highlight/dehighlight accordingly)
Register the actual keyboard "press" when the user lifts their finger; that is, the touch ends
I am testing using the touch tracking methods like this:
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
[super beginTrackingWithTouch:touch withEvent:event];
NSLog(#"Begin for %#", [self label]);
return YES;
}
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
[super continueTrackingWithTouch:touch withEvent:event];
NSLog(#"Continue for %#", [self label]);
return YES;
}
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
[super endTrackingWithTouch:touch withEvent:event];
NSLog(#"End for %#", [self label]);
}
These methods are all called, except they are only ever called on the UIControl where the touch began.
What is the best way to recognise touches coming and going across all my buttons? Do I have to do it all via the parent view?
I'll select a better answer if offered... but in case anybody finds this by search, I've managed to get what I need this way:
Set userInteractionEnabled to NO for the button class (UIControl subclass)
Don't override any touch methods in the button class
Implement touchesBegan:withEvent:, touchesMoved:withEvent: and touchesEnded:withEvent: in the view controller
On each event, extract the location from the UITouch object
Iterate over all of the button subviews and find the one containing the touch location:
- (MyButton *)buttonForTouch:(UITouch *)touch
{
CGPoint windowLocation = [touch locationInView:keyboardView];
for (MyButton *button in buttons) {
if (CGRectContainsPoint([button frame], windowLocation)) {
return button;
}
}
return nil;
}
Having determined which button the user is interacting with, make the view controller send messages to the relevant buttons to adjust their appearance
If appropriate, keep a reference to the UITouch instance in touchesBegan:withEvent: so you can be sure that you're tracking the same one in the other methods
I think that you should have a single big UIControl which has different subviews (like UIButton) but tracks touches by itself like you did already but finds out which subview to highlight depending on the touch position.
I tried to use custom UIControl in my view controller. My custom class which subclasses the UIControl and allocate the instance for my custom control and adding in to my view controller's view by following code
I have implemented following delegates which returns for YES to ensure the continuous touch.
- (BOOL) beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{
[super beginTrackingWithTouch:touch withEvent:event];
return YES;
}
- (BOOL) continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{
[super continueTrackingWithTouch:touch withEvent:event];
return YES;
}
- (void) endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{
[super endTrackingWithTouch:touch withEvent:event];
}
- (void)cancelTrackingWithEvent:(UIEvent *)event
{
NSLog(#"Touch cancelled");
}
But - (void)cancelTrackingWithEvent:(UIEvent *)event get called when I am tracking. After that I should have to taken up my finger and drag again. then only I receive begin and continue tracking delegates
According to your question, While tracking,cancelTrackingWithEvent: get called. Right. Check your view or superview with Gesture call backs. If You've added pan Gesture, This type of problem will rise. That is your control touch will begin and get tracked upto this tracking change to panning.
To solve this issue, set tag to your view and cancel gesture call as below.
During your view creation
yourView.tag = CANCELVIEWTAG;
Cancel gesture if touch happen in your view.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (touch.view.tag == CANCELVIEWTAG) {
return NO;
}
return YES;
}
I am handling Touches delegates and UITapGestureRecognizer for single tap. Following are the methods. When I single tap on my View, I get three events in order of TouchesBegan, SingleTap, and TouchesEnded. Is there anyway to stop TouchesEnded event when I have SingleTap detected? Basicaaly I don't want to perform tasks in TouchesEnded if TouchesMoved didn't happen. I have done this using failTouchEnded BOOL variable in SingleTap and checking it in TouchesEnded but not sure if it is a good idea!
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
failTouchEnded = NO;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if(failTouchEnded) return;
}
- (void)GestureView:(GestureView*)view handleSignleTap:(UITapGestureRecognizer*)recognizer {
failTouchEnded = YES;
}
gestureRecognizer has a property cancelsTouchesInView. if it is YES (which is default) cancels the touches if the gesture recognizer recognizes the gesture. So you will get a touches canceled instead of touches ended. You should set delaysTouchesEnded to YES too if it is not YES