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
Please do not post the same thing multiple times. The board software automatically flags certain posts as needing moderator attention. This happens the most often for new users. I'm pretty sure this is made clear at the time you attempt to post. Posting the same thing over and over again just makes that many more posts the moderators have to weed through later. This makes us sad. Don't make us sad. If your post/thread doesn't appear, just wait a while. Don't post it again. If it hasn't shown up by the next day, then you can try again. I normally go through posts in the mornings, and try to check a few times throughout the day, but I'm not here 24/7. There will typically be a significant delay before posts are approved. Just be patient.

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

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..
  • 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;145250 said:
    ....
    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.