Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In with Google Sign In with OpenID

FYI, How to pass touch events to UIWebView

bharath2020bharath2020 Posts: 151Registered Users
edited July 2010 in iPhone SDK Development
I was wondering how to pass touch events to UIWebview and here it is

UIWebview does not handle the touch event, instead it is some other view (i.e UIWebDocumentView) which handles the events. But, many people wonder, including me, how this undocumented, private object come into picture.

And the answer is UIWebview seems to override the hitTest:withEvent: method which on invoked returns the UIWebDocumentView, which means that all the subsequent touch events will be routed to UIWebDocumentView

Now how do we by pass this situation, so that one of our view class should get control over the touch event?

This can be done by subclassing the UIWebview and overriding the hitTest:withEvent method and invoking super class method
-(void)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
    _responderView = [super hitTest:point withEvent:event];//capture the view which actually responds to the touch events

   return self;//pass self so that the touchesBegan,touchesMoved and other    events will be routed to this class itself
   
}


//override touch events
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
  [ _responderView touchesBegan:touches  withEvent:event];
}


Hope this helps
Post edited by bharath2020 on
Bharath<br />
iOS Blog : <a href="http://iphone2020.wordpress.com" target="_blank">http://iphone2020.wordpress.com</a>;

Replies

  • pulaskeetpulaskeet Posts: 2New Users
    edited November 2009
    A+ post, worked well for me. This is a very efficient way of doing this, since many posts refer to private APIs which are grounds for App Rejection.
  • pulaskeetpulaskeet Posts: 2New Users
    edited November 2009
    After I implemented the overridden hitTest method, I ran into a few problems. Namely, the responderView wouldn't receive any messages after touchesBegan, which made me think that there were some private methods being called that we aren't allowed to interact with.

    The natural (and legitimate) way to deal with these private methods is to setup a dummy class that forwards any invocation methods to the actual responder class. To get a clear idea of what I'm talking about, look up the forwardInvocation method in the NSObject Class Reference.

    Below is the solution that gave me 100% control over any methods I wanted, while steering clear of private APIs and method swizziling.
    @interface ResponderWrapper : NSObject {
    	UIView *responderView;
    }
    
    - (id)initWithResponderView:(UIView*)aResponderView;
    @end
    
    @implementation ResponderWrapper
    
    - (id)initWithResponderView:(UIView*)aResponderView {
    	if (self = [super init]) {
    		responderView = [aResponderView retain];
    	}
    	return self;
    }
    
    - (void)dealloc {
    	[responderView release];
    	[super dealloc];
    }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    	[responderView touchesBegan:touches withEvent:event];
    	NSLog(@"touches began");
    }
    
    - (BOOL)respondsToSelector:(SEL)aSelector {
    	return [responderView respondsToSelector:aSelector];
    }
    
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
        return [responderView methodSignatureForSelector:aSelector];
    }
    
    - (void)forwardInvocation:(NSInvocation *)anInvocation {
    	if ([responderView respondsToSelector:anInvocation.selector]) {
    		[anInvocation invokeWithTarget:responderView];
    	}
    }
    
    @end
    
    @implementation DLWebView
    
    - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event {
    	UIView *responderView = [super hitTest:point withEvent:event];
    	return [[[ResponderWrapper alloc] initWithResponderView:responderView] autorelease];
    }
    
    @end
    
    

    DLWebView is nothing more than a subclass of UIWebView, and for simplicity I defined the wrapper object in the same class.
  • bharath2020bharath2020 Posts: 151Registered Users
    edited November 2009
    You have to override all the touches event from Began,Moved,Cancel,Ended and then route to the Private view or the ResponderView..

    But your solution of forward invocation is a class which eliminates the need to override the methods even if some new one are added in future, and hence Bug free..

    Thanks for sharing it..
    Bharath<br />
    iOS Blog : <a href="http://iphone2020.wordpress.com" target="_blank">http://iphone2020.wordpress.com</a>;
  • kidzxkidzx Posts: 2New Users
    edited February 2010
    First off excellent method to intercept touches on UIWebview. I suddenly have problem when using two fingers to pinch zoom , the web doesnt get re-rendered. Do you guys face the same problem?
  • johnlikesitjohnlikesit Posts: 12Registered Users
    edited March 2010
    pulaskeet wrote: »
    ....

    Do you have any tips for my on how do I implement this with my app :)

    Thanks!
  • reeconreecon Posts: 2New Users
    edited July 2010
    How to use that code, do you have some example implementation for it? thanks :)
Sign In or Register to comment.