Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIView touch handling behavior changed with Xcode 4.2?

Tags:

ios

ios5

xcode4.2

I upgraded my iPad to 5.0 a couple days ago, and upgraded Xcode to 4.2 at the same time so I could continue to test my apps. Now I am having problems with touch code in several apps that worked with previous versions of Xcode.

I subclassed UIImageView to add some dragging features by overriding -(void)TouchesBegan and -(void)TouchesMoved. I did not override -(void)TouchesEnded in the subclass, but handled that in the view controller for the view that contains the image view.

I pulled the subclassed UIImageView into a new project for testing, and have narrowed down the issue to the fact that the parent UIView (the template created by Xcode) does not seem to be forwarding touch events to the view controller (also created by Xcode).

If I add this to my subclass:

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touches ended event in ImageToDrag");
    [self.nextResponder touchesEnded:touches withEvent:event];
}

and this to my parent view's view controller:

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touches ended event in ViewController");
}

when I let go of the image I am dragging around the screen, I get the "touches ended event in ImageToDrag", but not the log from the view controller.

However, if I intentionally skip over the view by doing this in the subclassed view:

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touches ended event in ImageToDrag");
    [[self.nextResponder nextResponder] touchesEnded:touches withEvent:event];
}

then I get both log entries.

The only explanation I can come up with is that for some reason, UIView is consuming the touchesEnded event and not passing it to the view controller.

I have verified that exclusiveTouch is set to NO, and userInteractionEnabled is set to YES on the parent view and the subclassed UIImageView.

I have also tested compiling for iOS 5.0 and iOS 4.2, and deploying the test app to both an iOS 5 iPad and iOS 4.3.1 iPad.

The only way I have been able to get the touch event to the viewController is by skipping over the view and using the double nextResponder in the subclass. Although that method functions, it seems like a hack to me and I'm sure it will come back to bite me later.

Has anybody else seen this behavior? Is there any way for me to find out what the UIView is doing with my touch events?

Thanks, Dan

like image 461
dlenhard Avatar asked Oct 16 '11 20:10

dlenhard


2 Answers

I've been trying to track down the a similar issue for the last few hours. Finally managed to solve it with the help of this post

Actually it looks like I just managed to solve it, using the hint from https://devforums.apple.com/message/519690#519690
Earlier, I just forwarded the touchesEnded event to self.nextResponder. When I added touchesBegan, Moved, Cancelled handlers with similar implementations as the touchesEnded, the event seems to bubble up to the root view controller.
So I guess on iOS5, views discard touchesEnded events when they have not seen the relevant touchesBegan.

I didn't need to add Moved/etc., I just forwarded on TouchesBegan, and then TouchesEnded start working again!

like image 111
Danny Tuppeny Avatar answered Oct 19 '22 23:10

Danny Tuppeny


Some touch handling did chance in iOS 5.0; especially if you re-link your application against the 5.0 SDK.

There's a section UIView's touch handling methods that says this:

If you override this method without calling super (a common use pattern), you must also override the other methods for handling touch events, if only as stub (empy) implementations.

So if you do one, you need to do them all. I know UIKit started taking steps to make sure this was the case in 5.0.

So I'd start there - override all the methods on your view and see what happens.

like image 45
Chris Parker Avatar answered Oct 19 '22 23:10

Chris Parker