I have a UIWebView that displays a generated html table. When the user taps on a cell in the html table, my app needs to know which cell they've tapped, and the (x,y) coordinate of the tap location so I can display a popover at that point.
I've implemented shouldStartLoadWithRequest in my UIWebView delegate. In my web page, I've embedded javascript code that captures the touch event and passes what should be the (x,y) coordinate of the touched point in a URL request as follows:
var x, y;
function init()
{
// Add an event listener for touch events - set x and y to the coordinate of the touch point
document.addEventListener('touchstart', function(event) {
x = event.touches[0].clientX;
y = event.touches[0].clientY;
}, false);
}
function cellTapped(event)
{
window.location.href="file://myapp/dostuff?x=" + x + "&y=" + y;
}
In my html table, each cell gets an onclick event that calls cellTapped():
<td onclick="cellTapped(event)">...</td>
So whenever the user touches anywhere in the UIWebView, I get the coordinate of the touch point, which I save off in x and y. If they touch within one of the table cells, I receive the touch event (which sets x and y), then cellTapped() gets called and I set window.location.href, passing the (x,y) coordinate into my app.
This all works beautifully. Unless the user has zoomed or scrolled the UIWebView. When they zoom or scroll, the x and y coordinates I'm getting from event.touches[0].clientX and event.touches[0].clientY are off by some varying number of pixels (varies with the amount of zoom and how far up/down or left/right the web view is scrolled).
Is there some way to determine the zoom ratio and scroll position of the web view so that I can adjust my x and y coordinates accordingly? The zoomScale
and contentOffset
properties from UIScrollView do not seem to be exposed in UIWebView.
Use UIGestureRecognizerDelegate method:
Add UIGestureRecognizerDelegate in declaration file (i.e. your .h file)
Step 1: Just set the delegate of gestureRecognizer: (in .m file)
UITapGestureRecognizer *webViewTapped = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapAction:)];
webViewTapped.numberOfTapsRequired = 1;
webViewTapped.delegate = self;
[webView addGestureRecognizer:webViewTapped];
[webViewTapped release];
Step 2: Override this function: (in .m file)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
Step 3: Now implement the tapAction function:
- (void)tapAction:(UITapGestureRecognizer *)sender
{
CGPoint point = [sender locationInView:self.view]; // get x and y from here
}
EDIT: In iOS 5 and above, the scrollView property of UIWebView is exposed and accessible so this becomes a non-issue. In my case, I still need to support devices running iOS 4 (believe it or not...), so the following solves it for older versions.
By looping through the subviews of my UIWebView
, I can find the underlying UIScrollView
, then use its zoomScale
and contentOffset
properties to find the zoom and scroll position:
for (UIView *view in myWebView.subviews)
{
if ([view isKindOfClass:[UIScrollView class]])
{
// Get UIScrollView object
scrollview = (UIScrollView *) view;
// Find the zoom and scroll offsets
float zoom = scrollView.zoomScale;
float xOffset = scrollView.contentOffset.x;
float yOffset = scrollView.contentOffset.y;
}
}
I don't know if Apple would approve of this for app store submission, since I assume they had their reasons for not exposing the underlying UIScrollView
object, but it does solve my problem. My app is distributed under an Enterprise license anyway, so app store submission isn't an issue for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With