Sunday, October 18, 2009

Minor touch improvements

In this blog post I'm returning to the touch window code to show you a couple of improvements that were needed.

First, there was the issue of stopping the list halfway through a scroll. If you start dragging the list and then stop, wait a little and then release the finger or stylus, the list would still scroll. This is not an intended (nor intuitive) behavior: the user scrolls the list up to a position and he / she wants it to stay put by stopping the finger / stylus for a fraction of a second and then releasing it.

The second issue happened when the list was "bouncing back" if you forced it to scroll down from the top (or scrolling up from the bottom). Under some occasions you could actually stop the list from scrolling back to its "rest" position leaving it in an awkward state.

To solve the first issue I changed the bulk of the code in the CTouchGesture class and turned it into a state machine with four inputs:
  1. Press - The user pressed the finger / stylus
  2. Move - The user is dragging the finger / stylus
  3. Release - The user released the finger / stylus
  4. Timer - Called every 200 ms in order to check transient conditions
Each input is implemented by a method with the same name and the novelty here is that each of the first three returns a value of GestureType (NoGesture, ClickGesture, FlickGesture). The return type is used by the CTouchWindow mouse event handlers to determine what to do (nothing, a click or a flick). When flicking through the list, the CTouchGesture returns the delta movement through the new GetDelta function.

By implementing the gesture recognition as a state machine we get a much better chance of determining and handling the harder to detect situations, such as:
  • Input noise such as when the user flicks and accidentally releases the screen for a very short period. This is now handled by the code and the state machine assumes that the previous flick is still happening.
  • Intermediate motion stop, such as when the user is flicking and stops halfway. This situation is detected by the timer event that essentially resets all displacement and time accumulators and assumes that the user wants to do nothing (this is not interpreted as a click, of course).
Finally, I changed the code a little bit so that it does not allow the list to be in an "unnatural" position. Whenever the list stops it is checked for such a situation (showing the canvas to the top or bottom when the list is larger than the window). When such a situation is detected, the list is automatically scrolled back into position.

To illustrate all of this, I turned back to the AppStart sample simply because it has a bigger list. Here it is for your viewing pleasure (or not...):

Sample code: (166 KB)

No comments: