Custom Gestures: Going Beyond Swipe
So by now we have all grown accustomed to flicking our fingers around with wild abandon on our phone to just about do everything. Do you even remember what a stylus is used for? Unless you are working with big heavy gloves on, or need a stylus for signature capture or something else, chances are your users will have to navigate through your application by using their fingers for just about everything. Yeah sure, tap here to press a button, swipe here to scroll the content - that is child's play. Want to let your user swipe from the upper right corner to the lower left corner to mark a task complete? No problem. How about make a gesture like a frown and it does a sequence of events like scan a bar code, take a picture of what you scanned and then reverses the display so that the customer can sign for a package. Now we are talking. What I am talking about is enabling you, the application developer the ability to define your own gestures and actions to take with them - all in a few lines of code.
Overall the process to use custom gestures is to:
1) Define a gesture by setting some properties
2) Execute a gesture.create() to enable it
3) Execute some code when the gesture is triggered
Defining a Gesture:
There are three types of gestures that you can create: Linear, Circle and Hold. You can pretty much consider the Linear gesture to be the same as a swipe, however you have the great control of direction as well as where the starting and stopping positions of the gesture are expected to be. So instead of just having a swipe left-right up-down and vice versa, you can do things like swipe-diagonal (any direction) or things like region level swipe control. Maybe a swipe left-right on a section of the UI means to erase the whole entry while a swipe from left-right on the top of the UI means to move to the next record. Pretty cool huh? The next type of swipe is called Circle. This type is very similar to the Linear gesture except instead of straight lines, you can define circular patterns. Maybe you have the standard linear gestures enabled to scroll content, but you want a semi circle to do some sort of series of tasks. The last gesture type is called Hold. This gesture allows you to register for press and hold patterns. You can define location as well as how long a hold should be in order for it to be trigger. So maybe a short hold means - done with current task, but a long hold means quit the application and go to the main menu. Its up to you to be as creative as you want. But remember it should be something that is easily remembered by the user so that they can take advantage of them.
Using preset Gestures:
RhoElements comes with some predefined gestures for all of the three types. Be sure to look at the help file for a list of current predefined gestures. The 'preset' property is used to specify one of the preset values below. When a gesture definition is started using the 'type' tag its parameters are initially set to the preset shown as default. When a preset is specified for a gesture, including when it is first created, its ID is set to [gesture name]-[default preset name]. E.g. a new linear gesture will have the ID 'linear-left-right'. This can be replaced (as can any preset value) by a subsequent parameter tag.
GESTURE POSSIBLE VALUES DEFAULT
Linear left-right, right-left, top-bottom, bottom-top left-right
Circle happy*, sad* happy
Hold center center
The following example below enables a preset linear gesture for a swipe that starts at the top of the screen and ends at the bottom of the screen. When someone swipe in that direction, the onGesture function will be executed. if you swiped in any other direction, then no gesture event will be executed.
gesture.detected = 'onGesture(%json)'; // Enable the event
gesture.type = 'linear'; // this indicates what type of gesture it is
gesture.preset = 'top-bottom'; //this indicates what predefined gesture properties to use
gesture.create(); // this creates the gesture
Custom Defined Gestures:
So now let's say we want to provide a diagonal swipe gesture for our application. For that to be enabled, we will add a few more property definitions which basically indicate the start and stop areas we would be looking for. Note:that this also defines the direction of the gesture. For this example we will setup a diagonal linear gesture to start at the top left upper corner of the screen and end at the bottom right corner.
gesture.type = 'linear'; // Defines type of gesture
gesture.id = 'swipe-diag'; // To be used in the onGesture event to distinguish each gesture
gesture.startX = screen.width * .10; // using screen object so that gesture is size independant
gesture.startY = screen.height * .10; // top upper left corner
gesture.endX = screen.width * .90; // bottom lower right corner
gesture.endY = screen.height * .90;
gesture.diagnostics = true; //turning on diagnostics
gesture.create();
Notice that I turned on the diagnostics by executing a gesture.diagnostics = true. This is a very helpful feature for seeing if you defined the gesture properly but also to see what was detected. Of course you would not leave this on in your application. You will see something like:
The blue line is the gesture line with start and stop points indicated by a blue dot. The rectangles are areas that the gesture will be detected. You can modify the gesture recognition area by the properties regionWidth and tolerance depending on the type of gesture you are using. For the most part the default values will probably be good enough, but if you want fine grain control, you can play around with these settings to get the desired behavior you want. The above picture is what you would see before you did a swipe. After I do a swipe it would look like:
Notice a new green line as well as shaded portions of the rectangles. The green line is the actual path you swiped. At the start of the line is a number that indicates the "skew" and the second number represents the "deviation". The skew is essentially the angle that is caused by the line you swiped and the defined gesture line. You can define what is acceptable by setting gesture.skew=#. The default value is "20". Anything that is outside this value would not trigger a gesture event. The deviation basically indicates how straight the gesture was, opposed to being a wavy line. The lower the number the straighter the gesture was. The shaded rectangles indicate the areas that the gesture went through.
Linear gestures are pretty easy to setup, but don't forget about the hold and circle gesture. Maybe in you application you want to have the four corners of the device screen be "hot spots". This can easily be accomplished by doing:
gesture.type='hold';
gesture.centerX=screen.width * .10;
gesture.centerY=screen.width * .10;
gesture.id="press-top-left";
gesture.diagnostics = true;
gesture.create();
gesture.type='hold';
gesture.centerX=screen.width * .80;
gesture.centerY=screen.height * .10;
gesture.id="press-top-right";
gesture.diagnostics = true;
gesture.create();
gesture.type='hold';
gesture.centerX=screen.width * .80;
gesture.centerY=screen.height * .80;
gesture.id="press-lower-right";
gesture.diagnostics = true;
gesture.create();
gesture.type='hold';
gesture.centerX=screen.width * .10;
gesture.centerY=screen.height * .80;
gesture.id="press-lower-left";
gesture.diagnostics = true;
gesture.create();
Will yield something like:
Hope you found this useful. Share some of your custom gesture implementations in the comments section of this blog.
Robert Galvin
2 Replies
The link is updated now and it should get you the newer build. Just download the mdz and you can follow the similar procedure like before.
Great blog topic, Rob. I keep meaning to put together a sample to show how to create a rolling menu using the 'Hold' gesture. This would make use of the incrementing counter that is fired on a regular interval if you continue to hold on the screen and then another event when your finger is lifted form the screen. Yep, definitely need to write that sample...watch this space!!!