Gestures

Using Cascades controls is a good way to handle common touch interactions. In some situations, you might want to change these interactions or add interactions to noninteractive controls (such as containers or labels). You can listen for and respond to specific touch interactions called gestures. A gesture is a type of touch event that represents a simple, complete action that users can perform. When you're designing your app, you should always consider how gestures are used in BlackBerry 10 .

High-level gestures

For some of the most common gestures, Cascades provides a set of high-level APIs to make the gestures easy to capture and respond to. The supported gestures are as follows:

  • Tap
  • Double-tap
  • Pinch
  • Long press (press-and-hold)

Supporting gestures can be a good way to enhance the user experience of your apps. You can support interactions that users have come to expect from apps on mobile devices, and provide an intuitive, easy-to-use interface.

Consider an app that lets users browse a list of photos. When a user views a single photo, a double tap might resize the photo so that it fills the entire screen, and a pinch might let the user zoom in and out of the photo. A long press could display a menu that lets the user send the photo to a friend or save it in an album. By anticipating the things that users want to do in your app and supporting gestures that users expect, you can provide an exceptional user experience.

Each supported gesture has a corresponding handler class:  TapHandler DoubleTapHandler , PinchHandler , and  LongPressHandler . These handler classes all inherit from GestureHandler , which is the base class for gesture handlers.

Diagram showing the class structure of the GestureHandler class and its subclasses.

When you want to listen for a gesture, you add the appropriate handler to the UI control that users interact with. Every object that inherits from  VisualNode  includes a gestureHandlers list property, and you can use this property to add gesture handlers to the object.

Each gesture handler emits a signal (or multiple signals) when its gesture is detected. A TapHandler simply emits the  tapped()  signal when a tap occurs, but a PinchHandler emits signals such as pinchStarted()  (when a user places a second finger on the screen to start a pinch) and pinchUpdated()  (when the user moves one or both fingers while touching the screen).

Each signal includes an object parameter that corresponds to the type of event that occurred: TapEvent DoubleTapEvent PinchEvent , and  LongPressEvent . These objects contain information about the event, such as its location and the time it occurred. For pinch gestures, the PinchEvent includes properties for the distance, rotation, and midpoint of the pinch gesture.

Here's how to add a handler to respond to pinch gestures on an  ImageView . When a pinch gesture is detected on the ImageView, the pinchRatio property of the PinchEvent is used to increase or decrease the scale of the image as the pinch expands or contracts.

import bb.cascades 1.0
 
Page {
    Container {
        // The top-level container uses a dock layout so that the
        // image can always remain centered on the screen as it
        // changes size
        layout: DockLayout {}
         
        ImageView {
            id: myImage
 
            // This custom property stores the initial scale of the
            // image when a pinch gesture begins
            property double initialScale: 1.0
             
            // This custom property determines how quickly the image
            // grows or shrinks in response to the pinch gesture
            property double scaleFactor: 0.8
 
            horizontalAlignment: HorizontalAlignment.Center
            verticalAlignment: VerticalAlignment.Center
 
            imageSource: "asset:///images/myImage.png"
             
            gestureHandlers: [
                // Add a handler for pinch gestures
                PinchHandler {
                    // When the pinch gesture starts, save the initial
                    // scale of the image
                    onPinchStarted: {
                        myImage.initialScale = myImage.scaleX;
                    }
                     
                    // As the pinch expands or contracts, change
                    // the scale of the image
                    onPinchUpdated: {
                        myImage.scaleX = myImage.initialScale +
                                ((event.pinchRatio - 1) *
                                    myImage.scaleFactor);
                        myImage.scaleY = myImage.initialScale +
                                ((event.pinchRatio - 1) *
                                    myImage.scaleFactor); 
                    }
                }
            ]
        }
    }
}

In this example, only the slots that handle the pinchStarted() and pinchUpdated() signals are specified (0 is specified for the other slots), but you could add slots for the pinchEnded() and pinchCancelled() signals as well. For simplicity, it's assumed that the ImageView and the slot functions (along with the variables initialScale and scaleFactor) are declared in a corresponding header file.

// In your application's source file
 
// Create the root page and top-level container
Page* root = new Page;
Container* topContainer = Container::create()
        .layout(DockLayout::create());
 
// Create the image to scale using pinch gestures
myImage = ImageView::create("asset:///images/myImage.png")
           .horizontal(HorizontalAlignment::Center)
           .vertical(VerticalAlignment::Center);
 
// Create the pinch handler, connect its pinchStarted() and 
// pinchUpdated() signals to slots, and add the handler
// to the image
PinchHandler* pinchHandler = PinchHandler::create()
        .onPinch(this,
            SLOT(onPinchStart(bb::cascades::PinchEvent*)),
            SLOT(onPinchUpdate(bb::cascades::PinchEvent*)),
            0,
            0);
myImage->addGestureHandler(pinchHandler);
 
// Initialize a variable to store the initial scale of the image
// when a pinch gesture begins
initialScale = 1.0;
 
// Initialize a variable to determine how quickly the image grows or
// shrinks in response to the pinch gesture
scaleFactor = 0.8;
 
// Add the image to the top-level container, and add the top-level
// container to the page and display it
topContainer->add(myImage);
root->setContent(topContainer);
app->setScene(root);
 
...
 
// Define the slot function for the pinchStarted() signal
void App::onPinchStart(bb::cascades::PinchEvent* event)
{
    // Indicate that the event argument isn't used in this function,
    // to prevent a compiler warning
    Q_UNUSED(event);
     
    // When the pinch gesture starts, save the initial scale of
    // the image
    initialScale = myImage->scaleX();
}
 
// Define the slot function for the pinchUpdated() signal
void App::onPinchUpdate(bb::cascades::PinchEvent* event)
{
    // As the pinch expands or contracts, change the scale of the image
    myImage->setScaleX(initialScale +
                       ((event->pinchRatio() - 1) * scaleFactor));
    myImage->setScaleY(initialScale +
                       ((event->pinchRatio() - 1) * scaleFactor));
}

Not applicable

Last modified: 2015-05-07



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus