Implicit animations

An implicit animation occurs when a visual property of a control changes while your app is running. When you change a property that can be animated, the control doesn't update its appearance immediately to reflect the new value of the property. Instead, the control animates between the old and new values of the property. For example, if you change the opacity of a  Button from 1.0 to 0.0, the button fades out gradually, instead of immediately becoming invisible.

Cascades performs implicit animations automatically; you don't need to do anything except change the property that you want to animate. The amount of time that an implicit animation takes to complete is predefined and can't be changed.

Here's how to create a button that, when it's clicked, rotates using an implicit animation in QML:

import bb.cascades 1.0
 
Page {
    content: Button {
        text: "Rotate!"
 
        onClicked: {
            rotationZ = 155;
        }
    }
}

In C++, the process is similar, but involves a bit more code:

// In your application source file
 
// Create the root page and button
Page* root = new Page;
mButton = Button::create("Rotate!");
 
// Connect the button's clicked() signal to a slot. Make sure to test the
// return value to detect any errors
bool res = QObject::connect(mButton, SIGNAL(clicked()), this,
                            SLOT(onButtonClicked()));
Q_ASSERT(res);
 
// Indicate that the variable res isn't used in the rest of the app, to prevent
// a compiler warning
Q_UNUSED(res);
 
// Set the content of the page and display it
root->setContent(mButton);
app->setScene(root);

You also define the onButtonClicked() slot function in your application source file:

// A slot that handles a button click and rotates the button
void App::onButtonClicked()
{
    mButton->setRotationZ(155);
}

In your header file, you declare the Button variable and the onButtonClicked() slot:

Button* mButton;
 
public slots:
    void onButtonClicked();

When you change the value of a control's property, the control is animated visually to reach the new property value, but the property value itself is changed immediately. For example, if you change the translationX property of a  Label from 0 to 45, the value of the property is immediately set to 45. You'll then see the x position of the label change smoothly from 0 to 45 as the control is animated to reach the new property value.

You can use implicit animations for the following types of properties:

  • Properties that determine how a control looks, such as rotation, translation, and opacity
  • Properties that determine the layout of a control in a container, such as preferred width and preferred height

Here's how to change the layout of a container using an implicit animation, in QML. The container includes two buttons, and when the first button is clicked, the layout is changed from a left-to-right stack layout to a top-to-bottom stack layout.

import bb.cascades 1.0
 
Page {
    Container {
        id: container
         
        // Create a stack layout object for each layout that the app uses, and
        // add them to the attached objects list
        attachedObjects: [
            StackLayout {
                id: layout1
                orientation: LayoutOrientation.TopToBottom
            },
            StackLayout {
                id: layout2
                orientation: LayoutOrientation.LeftToRight
            }
        ]
         
        layout: layout1
         
        Button {
            text: "Click me!"
            onClicked: {
                container.layout = layout2;
            }
        }
        Button {
            text: "Don't click me"
        }
    }
}

Here's how to accomplish the same thing in C++.

// The variables mContainer, mStackLayout1, and mStackLayout2 are declared in a
// header file
 
Page* root = new Page;
mContainer = new Container;
 
// Create the layouts
mStackLayout1 = StackLayout::create()
        .orientation(LayoutOrientation::LeftToRight);
mStackLayout2 = StackLayout::create()
        .orientation(LayoutOrientation::TopToBottom);
mContainer->setLayout(mStackLayout1);
 
// Create the buttons and connect the first button's clicked()
// signal to a slot function. Make sure to test the return value to detect any
// errors
Button* myButton1 = Button::create("Click me!");
Button* myButton2 = Button::create("Don't click me");
bool res = QObject::connect(myButton1, SIGNAL(clicked()), this,
                            SLOT(onButtonClicked()));
Q_ASSERT(res);
 
// Indicate that the variable res isn't used in the rest of the app, to prevent
// a compiler warning
Q_UNUSED(res);
 
// Add the buttons to the container
mContainer->add(myButton1);
mContainer->add(myButton2);
 
root->setContent(mContainer);
app->setScene(root);
// A slot that handles the button click and changes the layout, and is
// also declared in a header file
 
void App::onButtonClicked()
{
    mContainer->setLayout(mStackLayout2);
}

Controlling implicit animations

You can use implicit animations to create smooth transitions and effects without writing a lot of code, but you don't have very much control over the animation that occurs. You can't change its duration or specify a sequence of animations that should occur one after another. However, you can use the ImplicitAnimationController class to define whether you want a particular visual property to use implicit animations. This class lets you turn on and turn off implicit animations for all visual properties of a control, or for specific properties only.

You can use an ImplicitAnimationController to enable or disable implicit animations for the following properties of a control:

  • translationXtranslationY
  • rotationZ
  • scaleXscaleY
  • pivotXpivotY
  • opacity

You can't enable or disable implicit animations for layout properties (such as preferredWidth and preferredHeight) using ImplicitAnimationController.

Using ImplicitAnimationController in QML

In QML,  ImplicitAnimationController includes two properties: propertyName and enabled. The propertyName property is a string that specifies the visual property that you want to control, and must be one of the visual properties that are listed in the previous section. The enabled property is a Boolean value that indicates whether implicit animations are enabled for the property.

You can add an ImplicitAnimationController to any UI control (that is, any control that inherits from the  UIObject class). You specify ImplicitAnimationController objects by using the attachedObjects list for the control. The attachedObjects list allows you to use C++ objects directly in QML without creating a custom class and registering it for use in QML. To learn more about the attachedObjects list, see QML and C++ integration.

Here's how to create a button that, when it's clicked, moves slightly to the right. The button uses an ImplicitAnimationController to prevent this horizontal movement from using an implicit animation.

import bb.cascades 1.0
 
Page {
    content: Container {
        Button {
            text: "Click me"
             
            attachedObjects: [
                ImplicitAnimationController {
                    propertyName: "translationX"
                    enabled: false
                }
            ]
             
            onClicked: {
                translationX += 20;
            }
        }
    }
}

If you omit the propertyName property in ImplicitAnimationController, then all implicit animations for the control are enabled or disabled according to the value of the enabled property. Here's how to create a button that moves and rotates when it's clicked. Implicit animations for the movement and rotation are enabled or disabled based on the state of a toggle button.

import bb.cascades 1.0
 
Page {
    content: Container {
        Button {
            text: "Click me"
             
            attachedObjects: [
                ImplicitAnimationController {
                    id: allAnimationController
                    enabled: animationToggle.checked
                }
            ]
             
            onClicked: {
                translationX += 20;
                translationY += 20;
                rotationZ += 20;
            }
        }
         
        ToggleButton {
            id: animationToggle
            checked: true
        }
    }
}

Using ImplicitAnimationController in C++

In C++, you create an  ImplicitAnimationController by using a builder and specifying the following:

  • The control that the ImplicitAnimationController applies to
  • The name of the property that the ImplicitAnimationController applies to (optional)
  • Whether implicit animations should be enabled or disabled

Similar to the QML implementation, if you don't specify a property name, the ImplicitAnimationController applies to all visual properties of the control.

Here's how to create a button that, when it's clicked, rotates to the right and fades to an opacity of 0.5. Both of these properties use their own ImplicitAnimationController objects to disable implicit animations. Because the ImplicitAnimationController objects are created inside the scope of onButtonClicked(), they are effective only while this function executes. If you change the rotation and opacity values elsewhere in the app, implicit animations would be enabled for those changes.

// The variable mButton is declared in a header file.
 
// Create the root page and button
Page* root = new Page;
mButton = Button::create("Click me");
 
// Connect the button's clicked() signal to a slot function. Make sure to test
// the return value to detect any errors.
// If any Q_ASSERT statement(s) indicate that the slot failed to connect to 
// the signal, make sure you know exactly why this has happened. This is not
// normal, and will cause your app to stop working!!
bool res = QObject::connect(mButton, SIGNAL(clicked()), this,
                            SLOT(onButtonClicked()));
                            
// This is only available in Debug builds.
Q_ASSERT(res);
 
// Indicate that the variable res isn't used in the rest of the app, to prevent
// a compiler warning.
Q_UNUSED(res);
 
// Set the content of the page and display it
root->setContent(mButton);
app->setScene(root);
// A slot that handles the button click, and rotates and fades the
// button. This slot is also declared in a header file.
 
void App::onButtonClicked()
{
    ImplicitAnimationController rotateController = 
            ImplicitAnimationController::create(mButton, "rotationZ")
                                                 .enabled(false);
    ImplicitAnimationController opacityController =
            ImplicitAnimationController::create(mButton, "opacity")
                                                 .enabled(false);
    mButton->setRotationZ(20);
    mButton->setOpacity(0.5);
}

Last modified: 2013-12-21

comments powered by Disqus