I recently released an update of the HTML5 / PhoneGap application I wrote a few months ago to the marketplace. This update fixed the location detection issue, where the marketplace certification process failed to detect that the application was using geolocation data via the browser (this issue has been fixed in PhoneGap 1.2), plus a few cosmetic improvements.
This application still exhibits a few UI quirks that make it fairly obvious that this is not a native application, the first is the gray box that appears whenever a link is clicked, the second is the overall responsiveness - there is a short delay between clicking on links / buttons and the application responding. It is this responsiveness that I would like to tackle in this blog post. This delay unfortunately gives the impression that your application is less responsive than it actually is!
So where does this delay come from?
Despite the rise in popularity of touch interfaces, much of the web is still designed for interaction with a mouse and keyboard, with the DOM exposing events for mouse-up, mouse-down and click user interactions. The Windows Phone 7 browser control captures touch interactions and translates these into the required mouse events, firing them on the DOM element being interacted with. However, the browser itself also needs to support gestures such as pan, pinch-zoom and double-tap zoom.
Now consider the double-tap zoom feature, where the user taps twice in quick succession to zoom the web page by some fixed amount. If the DOM click event were fired on the first tap, this would cause a navigation to occur if an anchor element were tapped. This is certainly not the desired behaviour! Again, there is no way to 'cancel' an event once it is fired, so the only solution to this problem is, when the user first taps the screen, pause for a few hundred milliseconds to see if they tap a second time. Only after this pause is it safe to pass the interaction onto the DOM, firing a click event on the relevant DOM element.
Stock image courtesy of lovetheson
The need to handle gestures in the native layer causes numerous issues for the browser event handling. Thankfully these issues are relatively minor for most websites, but if your aim is to create a HTML-based application with a native look and feel, these issues become quite major.
The problem I want to tackle in this blog post is that of the click DOM event firing delay to support the double-tap gesture. With HTML5-based applications you will typically want to disable pinch zoom, double-tap zoom and (optionally) scrolling as I described in a previous blog post. As a result your application has no need for the double-tap and pinch gestures and we are safe to short-circuit this behaviour, immediately raising DOM click events when the user taps the screen.
My solution follows a similar approach to the utility class I wrote for suppressing pan / zoom, where event handlers are added to the
Border that sits within the
WebBrowser control visual tree:
\-WebBrowser \-Border \-Border \-PanZoomContainer \-Grid \-Border (*) \-ContentPresenter \-TileHost
In order to forward Tap gestures to the browser, we can add event handlers to the Border element, then use
InvokeScript to pass this onto the DOM rendered within the
elementFromPoint function which allows you to hit test the DOM. The IE9 DOM interface also exposes a non-standard
click function which invokes any click event handlers, this will cause an anchor element to navigate. Putting it together, if you have an anchor element at
(x=100, y=100), you can cause it to navigate using the following simple code:
To use it within a PhoneGap application, simply create an instance as follows:
The net result is that your application becomes more responsive, with the browser immediately navigating links when they are first tapped.
I have updated the HTML5 SandwichFlow application I blogged about a few weeks ago to use this FastClick code. You can download the complete example here: HTML5SandwichFlow.zip
Regards, Colin E.