touchesEnd does not get called bit touchesBegin and touchesMoved does get called - ios

I'm trying to do a drag in ios. If the drag movement was a short distance, I was going to count the drag as a click event, by comparing the start x,y (from touchesBegan) to the x,y in touchesEnd.
It seems like touchesEnd never gets called. I put a break point to verify it and the break point never went off.
code:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSUInteger touchCount = [touches count];
NSUInteger tapCount = [[touches anyObject] tapCount];
[ self UpdateDrag];
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSUInteger touchCount = [touches count];
NSUInteger tapCount = [[touches anyObject] tapCount];
}
- (void) touchesEnd:(NSSet *)touches withEvent:(UIEvent *)event {
// this methes never gets called
NSUInteger touchCount = [touches count];
NSUInteger tapCount = [[touches anyObject] tapCount];
if (mDisplay==nil)
{
mDisplay = [[cDisplayYesOrNo_iPhone alloc]
initWithNibName:#"cDisplayYesOrNo_iPhone"
bundle:[NSBundle mainBundle]];
}
[ mDisplay SetUp];
[self presentModalViewController: mDisplay animated:NO];
}

Is - (void)touchesEnded: not - (void)touchesEnd:
https://developer.apple.com/library/ios/documentation/uikit/reference/UIResponder_Class/Reference/Reference.html#//apple_ref/occ/instm/UIResponder/touchesEnded:withEvent:

You need to edit touchesEnd to touchesEnded.
Also, for completeness, you need to consider whether you also need to respond to touchesCancelled which is called instead of touchesEnded in some circumstances.

Related

Neither touchesEnded nor touchesCancelled not called sometimes after touchesMoved

I Have one circular view in my application and I am moving some objects like graph in that circular view its work fine in 90% cases but at some cases its not calling TouchEnded and my reset graphs code is in TouchEnded methods so its unloaded at some point below is my code for touches delegate methods.
#pragma mark - Touch Events For Rotation of GRAPH
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch* touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
prevAngle = [Utilities angleBetweenPoint:touchPoint toPoint:self.view.center];
/// convert negative angle into positive angle
if(prevAngle < 0){
prevAngle = PI_DOUBLE + prevAngle;
}
//
[_viewStaticRadialPart hideToolTip];
}
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
CGFloat diffAngle, tempCurAngle, tempPrevAngle, curTransformAngle, newTransformAngle;
NSLog(#"touchesMoved");
// Get the only touch (multipleTouchEnabled is NO)
UITouch* touch = [touches anyObject];
// Track the touch
CGPoint touchPoint = [touch locationInView:self.view];
curAngle = [Utilities angleBetweenPoint:touchPoint toPoint:self.view.center];
/// convert negative angle into positive angle
if(curAngle < 0){
curAngle = PI_DOUBLE + curAngle;
}
prevAngle = curAngle;
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self resetViewsOnceRotationStops];
}
- (void)touchesCancelled:(nullable NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event
{
[resetViewsAfterTouchStops invalidate];
resetViewsAfterTouchStops = nil;
}
I am stuck here since last night so any help will be appreciated.
Thanks in advance.
I don't know the cause for this problem from core level.
But NSTimer can help us in
But I feel we can resolve this by adding setting / replace NSTimer instance while touchesMoved called and we can reset that timer on touchesEnded and touchesCancelled. So, in either case, your touchesEnded or touchesCancelled not called timer will do that job and your reset logic works as it should be expected.
Demo Source Code
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
NSLog(#"touchesMoved");
//Timer re-initialize code here
if (resetViewsAfterTouchStops) {
[resetViewsAfterTouchStops invalidate];
resetViewsAfterTouchStops = nil;
}
resetViewsAfterTouchStops = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(resetViewsOnceRotationStops) userInfo:nil repeats:NO];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
isTouched = NO;
[resetViewsAfterTouchStops invalidate];
resetViewsAfterTouchStops = nil;
[self resetViewsOnceRotationStops];
[self setUserInteractionOnSectorsAs:YES];
}
- (void)touchesCancelled:(nullable NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event
{
NSLog(#"touchesCancelled");
if(resetViewsAfterTouchStops)
{
[self resetViewsOnceRotationStops];
[self setUserInteractionOnSectorsAs:YES];
}
[resetViewsAfterTouchStops invalidate];
resetViewsAfterTouchStops = nil;
}
- (void) resetViewsOnceRotationStops
{
//your reset code will be place here
}
Try removing UIGestureRecognizer objects on that view if you are using any. UIGestureRecognizer objects interfere with touch events lifecycle.

Why can't I drag images?

I am working off of http://www.raywenderlich.com/33806/how-to-make-a-letterword-game-with-uikit-part-2 , and it says in reference to the view to add the following to the implementation:
int _xOffset, _yOffset;
For the initializer:
self.userInteractionEnabled = YES;
It also gives three methods to implement to handle dragging:
#pragma mark - dragging the tile
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint pt = [[touches anyObject] locationInView:self.superview];
_xOffset = pt.x - self.center.x;
_yOffset = pt.y - self.center.y;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint pt = [[touches anyObject] locationInView:self.superview];
self.center = CGPointMake(pt.x - _xOffset, pt.y - _yOffset);
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesMoved:touches withEvent:event];
}
Nothing seems to happen, though, when I touch one of the images and try to drag it around. It seems to never move.
There is more work than this to do; I want to do something specific based on where a dragged image is dropped. But right now I'm working on the smoke test, and I cannot see any change in the UI behavior from before when I added this code.
Thanks for any help,

Is it possible to find all the subviews that exist at a point on iphone?

I would like to be able to retrieve info on a tap, about all the different subviews that are placed in that tap spot. For example, if there was a background, and in front of it was a game character, I would like to be able to tap on that character, and it will retrieve the info saying that both the character and the background are in that tap spot.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//retrieve info about what other subviews lie behind at this point
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch=[touches anyObject];
CGPoint p=[touch locationInView:self.view];
NSLog(#"Coordiantes of Tap Point:(%f,%f)", p.x, p.y);
NSArray *anArrayOfSubviews = [self.view subviews];
NSMutableArray *requiredSubviewArray = [NSMutableArray array];
for (UIView *aSubView in anArrayOfSubviews){
if(CGRectContainsPoint(aSubView.frame, p)) {
//aSubView is there at point 'p'
[requiredSubviewArray addObject:aSubView];
}
}
// requiredSubviewArray contains all the Subviews at the Tap Point.
}
try this.it maybe helpful to you..
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//retrieve info about what other subviews lie behind at this point
NSLog(#"subviews--%#",[self.view subviews]); //it prints all subviews as Array
NSLog(#"superview--%#",[self.view superview]); //it prints superview of your view
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject]; // here you get all subviews on ur touchpoint
if ([touch view] == imageView) {
CGPoint location = [touch locationInView: self.view];
imageView.center = location;
}
}
/// To check both views are in one spot, use this
// CGRectContainsRect() and CGRectIntersectsRect().
You can try this one..
You can get all subviews if you use [self.view subviews]. You can compare those views frames with touch location.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint touchLocation = [touch locationInView:self.view];
startX = touchLocation.x;
startY = touchLocation.y;
for (UIView *view in [self.view subviews]){
//Here you can compare each view frame with touch location
}
}

difference of the two parameters in method like - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

when i try to figure out how to deal with the touches in iOS, i saw some code use the first parameter "touches" some uses the second one "[event allTouches]". so anyway, what's the difference between them. in what situation use the first one, what situation use the second one. THANKS!
here's more details:
// used the first parameter
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSUInteger touchCount = [touches count];
NSUInteger tapCount = [[touches anyObject] tapCount];
methodStatus.text = #"touchesEnded";
touchStatus.text = [NSString stringWithFormat:#"%d touches", touchCount];
tapStatus.text = [NSString stringWithFormat:
#"%d taps", tapCount];
}
// used the second parameter
-(void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event {
NSSet *allTouches = [event allTouches];
//...
}
The UIEvent has property called timestamp along with the touches. Apart from that I believe both are same.

Detect only double or single tap with UIViews?

I want to detect JUST double / single tap when the user touches a view.
I made something like this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint prevLoc = [touch ]
if(touch.tapCount == 2)
NSLog(#"tapCount 2");
else if(touch.tapCount == 1)
NSLog(#"tapCount 1");
}
But it always detect 1 tap before 2 taps. How can I detect just 1 / 2 tap?
Thanks for you help. I also found a way like that:
-(void)handleSingleTap
{
NSLog(#"tapCount 1");
}
-(void)handleDoubleTap
{
NSLog(#"tapCount 2");
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSUInteger numTaps = [[touches anyObject] tapCount];
float delay = 0.2;
if (numTaps < 2)
{
[self performSelector:#selector(handleSingleTap) withObject:nil afterDelay:delay ];
[self.nextResponder touchesEnded:touches withEvent:event];
}
else if(numTaps == 2)
{
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[self performSelector:#selector(handleDoubleTap) withObject:nil afterDelay:delay ];
}
}
It will help to define methods for single and double taps
(void) handleSingleTap {}
(void) handleDoubleTap {}
So then in touchesEnded you can call the appropriate method based on the number of taps, but only call handleSingleTap after a delay to make sure double tap has not been executed:
-(void) touchesEnded(NSSet *)touches withEvent:(UIEvent *)event {
if ([touch tapCount] == 1) {
[self performSelector:#selector(handleSingleTap) withObject:nil
afterDelay:0.3]; //delay of 0.3 seconds
} else if([touch tapCount] == 2) {
[self handleDoubleTap];
}
}
In touchesBegan, cancel all requests to handleSingleTap so that the second tap cancels the first tap's call to handleSingleTap and only handleDoubleTap will be called
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:#selector(handleSingleTap) object:nil];
Maby you can use some time interval. Wait with dispatching the event for (x)ms. If you get two taps in that time-period, dispatch a double-tap. If you only get one- dispatch single tap.

Resources