Extending Ext.Button for better UX and responsive tap

GT.FixedButton
==============

This extends the Ext.Button in Sencha Touch 2.0 for a different, more iOS like user experience. As the name suggests this works well for buttons that are fixed and not in a scrollable container. It might also work with buttons in a scrollable container but haven't tested yet.

1. The button fires on the tap event. This is not optimal because the user needs to tap the button and release it exactly on the same pixel, or else the tap event doesn't fire. There is a thread about using moveThrottle (http://www.sencha.com/forum/showthre...t=movethrottle) to give the tap event a tolerance:

But this code messes with the other touch events, making the carousel and all scrolling look choppy. Even if that choppiness was acceptable, a 3px or 5px tolerance still isn't good enough. Some users are "sloppy" tappers.

2. When you touch a button, the press state is added. Only when you let go (touchend), does the press state disappear. Even if you touch the button and drag your finger off, the press state remains. There is a fundamental flaw in the logic in that when the user sees the "press state" activated, they would expect the button to be "tapped" when they let go.

The Alternative
===============

This attempts to solve the issues by doing the following:

1. The tap zone is now larger than the button itself. This is done using a tapmask and is inspired by SunboX and Lim Chee Aun's post: http://cheeaun.com/blog/2012/03/how-...b-app#the-feel
2. Upon press, the tap zone is doubled.
3. The tap event is tied to touchstart and touchend. If you touch the button and then release and are still on tap zone, it will fire the tap event. The user can now be as "sloppy" as they want and there is a now a buffer zone around the button.
4. The press state is also tied to touchmove. If you activate the button press and then move your finger off the button, the press state disappears and the tap event won't fire.

Getting Started
===============

To use this, add the following to your app.js:

Code:

Ext.Loader.setPath({
'GT': 'GT'
});

From there, you will have access to the fixed button by using:

Code:

requires: ['GT.FixedButton']
//...
xtype: 'fixedbutton'
// these are default, only add if you are changing
tapMask: null, // change to true to see the zone, good for debugging
tapOverflowTop: 10, // in pixels
tapOverflowBottom: 10, // in pixels
tapOverflowLeft: 10, // in pixels
tapOverflowRight: 10 // in pixels

Great read! Definitely given me the inspiration to extend this some more to override the touchmove bug and create a touchend 50px "ring" around the button instead.

I'll work on making those dimensions configurable. That also solves a big issue in that it's hard to hit a small target on a smartphone. I've always used padding and an image to fake a larger initial tap area. I'll see about creating a mask that is a smaller "ring" around a button.

I've incorporated the latest changes so now the example is using a tapmask. Still need to tie it to x/y coordinates instead of the element itself due to the sencha bug. But it works great in Chrome/Safari. Check it out:

Updated FixedButton so that it's tied to X/Y coordinates so it now works in iOS. I'm assuming it will also work in Android/Blackberry as the code is pretty standard. Essentially when you tap a button, I record the offsets and height and width and then compare that to the x/y coordinates on touchmove and touchend.

One caveat is that this will unfortunately NOT work in a scrolling container as the scrolling changes the X/Y coordinate calculation. There needs to be a lot more logic and deeper integration into ST2 for this to work successfully in scrolling containers. Based on SunboX's post, we could port this UI over to be a good disclosure icon for a list but that's another day!