How to cancel a sequence of UITouch events?
Asked Answered
A

12

22

I have a UIImage view that responds to touch events. I want to cancel the touch sequence, i.e., further calls to touchesMoved:, if the touch goes outside of certain bounds. How can I do that?

I know that in touchesMoved: I can inspect the coordinates of the touch object and ignore it, but what I don't know is how to cancel the sequence altogether. I don't see any method documented in the Apple Developer UIResponder Reference that I can call to cancel a touch sequence.

Avelin answered 10/2, 2009 at 18:37 Comment(1)
Were you able to figure this out?Barclay
G
7

This solution may be a bit kludgy, but you could implement and manually call

- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

I am basing this solution loosely on some tweaking I did to the MoveMe sample app on Apple's iPhone sample code site where I modified the touchesMoved method to look like this:

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
     UITouch *touch = [touches anyObject];
     if ([touch view] == placardView)
         CGPoint location = [touch locationInView:self];
         placardView.center = location;
         // I added the following line:
         [self touchesCancelled:touches withEvent:event];
         return;
}
Glib answered 10/2, 2009 at 19:51 Comment(3)
Thanks, I'll give this a try when I get back to my mac. But is this going to cancel the subsequent touches events? It seems to me that after a manual call to touchesCancelled, the touchesMoved would still be called by the system.Avelin
Within the confines of the MoveMe sample code it will cancel the touch, but I believe you're right, touchesMoved would still be called. The more I think about it the less I think touchesCancelled is the right call.Glib
That doesn't work and "move" events keep coming ever after.Christchurch
S
4

Try temporary setting the UIImageView's userInteractionEnabled property to NO

Sabin answered 28/11, 2011 at 3:30 Comment(0)
E
3

You need to call [super touchesMoved:withEvent:] in order to let the super view clean up from the event but more importantly, you need to not call [super touchesCancelled:withEvent:].

Here's what I used on a cell to keep it from getting selected when I detected a swipe:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (!showingEdit) {
        if (IS_FAR_ENOUGH_TO_BE_A_SWIPE) {
            RESPOND_TO_SWIPE
            showingEdit = YES;
            [super touchesCancelled:touches withEvent:event];
        } else {
            [super touchesMoved:touches withEvent:event];
        }
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (!showingEdit) {
        [super touchesEnded:touches withEvent:event];
    }
}
Earnestineearnings answered 13/5, 2010 at 0:50 Comment(0)
K
2

I've faced the same problem recently and found a standard way to solve it. You can use [[UIApplication sharedApplication] beginIgnoringInteractionEvents] to stop delivering touchesMoved events to your whole app. Make sure to enable them using [[UIApplication sharedApplication] endIgnoringInteractionEvents] when you need to receive touches again.

Klingensmith answered 5/4, 2010 at 9:30 Comment(0)
R
2

I don't think it's possible because I don't see it documented and none of these solutions work.

Racemose answered 21/11, 2011 at 4:23 Comment(0)
C
1

"Brute force" solution depending if it suits your needs: Remove and re-initialize the subview that receives the touches or responds to them (of course take care of frame and content).

Cashier answered 24/3, 2013 at 20:56 Comment(0)
P
1

I achieve this by removing the view from its superview and adding it straight back.

[view retain];
UIView *sv = view.superview;
[view removeFromSuperview];
[sv addSubview:view];
[view release];

This breaks the responder chain to the view so any remaining touches will not be received on the view. The next touch will still be received as normal.

Plush answered 3/8, 2016 at 10:44 Comment(0)
T
0

On iOS5 there seems to be a private method in UITouch

-(void)setSentTouchesEnded:(BOOL)ended;

Depending on apple's implementation it could stop sending events

Another way of doing so would be using associative objects

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    if ([(NSNumber *)objc_getAssociatedObject(touch, &outKey) boolValue])
        return;
    if (sometouchisoutsideofview) {
        objc_setAssociatedObject(touch, &outKey, [NSNumber numberWithBool:YES], OBJC_ASSOCIATION_RETAIN);
    }
}
Tynan answered 25/11, 2011 at 18:44 Comment(0)
C
0

I was just trying to solve something like this, and found that none of the solutions listed her worked for me. The best i could manage was temporarily ignoring the touches, but then they resumed when the touch re-entered the view.

Finally solved it.

  1. Set up a boolean flag called "disabled"
  2. In touchedMoved, first check that the touch is inside the desired view. If it isn't, set the disabled flag to YES.
  3. Still in in touchedMoved, check the flag before performing your action. So, at this point, nothing will happen if they're outside the view.
  4. In touchesEnded, set the disabled flag to NO. So the touch sequence is effectively halted until user lifts their finger.

I guess this will work for you unless you have a specific reason for literally needing the touch sequence cancelled.

Craggie answered 13/1, 2013 at 14:41 Comment(1)
You can even do the UIControl-style tracking by using a single flag. Which feels more natural than if the entire event sequence was cancelled at once.Christchurch
E
0

This code will help you. I disable touch event in touchesMoved: method and I am enabling touch event in touchesCancelled: method

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
     UITouch *touch = [touches anyObject];
     .......
     .......
     Your code
     .......
     .......

     //Condition when you want to disable touch event

     [[UIApplication sharedApplication] beginIgnoringInteractionEvents];

     .......
     .......
     Your code
     .......
     .......
 }


- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [[UIApplication sharedApplication] endIgnoringInteractionEvents];
}
Embracery answered 21/8, 2014 at 10:31 Comment(0)
I
-1

You may create category to UITouch. You can to declare

@property (nonatomic,strong,readwrite) UIView *view;

And when you change touch.view to nil, for example, you can simulate end of dispatching touch events

Irvine answered 17/4, 2013 at 19:43 Comment(0)
R
-2

You can check that, the touch point locations are in CGRect (ie. points are in Rectangle of your imageview) or not. If they are not in that Rect, the touch will be cancelled.

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
 {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self.view];

    if (CGRectContainsPoint(myImageView, touchLocation))
    {
       lastPoint = [touch locationInView: myImageView];
    }

    NSLog(@"Last :%.2f - %.2f",lastPoint.x, lastPoint.y);   
  }

 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
 {
  CGPoint currentPoint;
  UITouch *touch = [touches anyObject];
  CGPoint touchLocation = [touch locationInView:self.view];

     if (CGRectContainsPoint(myImageView.frame, touchLocation))
     {
       currentPoint = [touch locationInView: myImageView];
     }
 }
Rhonarhonchus answered 24/11, 2011 at 5:44 Comment(1)
That code doesn't cancel further calls to touchesMoved:. It just ignores them.Racemose

© 2022 - 2024 — McMap. All rights reserved.