how to combine Behavior with sequential animation in qml

79 Views Asked by At

if you have 4 properties and each one has a Behavior block (that lets you animate if the corresponding property is changed ) if you change 4 properties then the animation will be parallel by default, but is it possible to make the Behavior blocks execute in sequence?

import QtQuick 
import QtQuick.Controls 


ApplicationWindow {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    Rectangle {
        id: root
        width:196
        height:196
        color:"lightgray"

        Rectangle {
            id: box
            width:48
            height:48
            x:10
            y:10
            color: "red"
            rotation:0
            MouseArea {
                id:d
                anchors.fill: parent
                onClicked: {
                    parent.x= parent.x==10 ? root.width - parent.width -10 : 10
                    parent.y= parent.y==10 ? root.height - parent.height -10 : 10
                    parent.rotation= parent.rotation==360 ? 0 : 360
                    parent.color=parent.color=="#ff0000" ? "teal": "red"

                }
            }

            Behavior on rotation {
                id:d1
                RotationAnimation {
                    duration: 500
                }
            }

            Behavior on x {
                id:d2
                NumberAnimation {
                    duration: 500
                }
            }
            Behavior on y {
                id:d3
                NumberAnimation {
                    duration: 500
                }
            }
            Behavior on color {
                id:d4
                ColorAnimation{
                    duration:500
                        }

            }
        
    }

}
}

I tried to `onClicked:{ ... d1.start() d2.start() ...

` but it doesn't make sense for Qml

2

There are 2 best solutions below

1
iam_peter On BEST ANSWER

Following this guide (Using Qt Quick Behaviors with States) I've used State and Transition instead of Behavior. You can simply replace the SequentialAnimation with ParallelAnimation to get your old behavior back.

This paragraph from the guide advises to use Transition and State to avoid unwanted behavior.

Testing the example by quickly and repeatedly moving the mouse in to and out of the colored rectangle shows that the colored rectangle will settle into a green color over time, never returning to full red. This is not what we wanted! The problem occurs because we have used a Behavior to animate the change in color, and our state change is trigged by the mouse entering or exiting the MouseArea, which is easily interrupted.

Rectangle {
    id: root
    width: 196
    height: 196
    color: "lightgray"

    Rectangle {
        id: box
        width: 48
        height: 48
        x: 10
        y: 10
        color: "red"
        rotation: 0

        property bool toggle: false

        MouseArea {
            id:d
            anchors.fill: parent
            onClicked: box.toggle = !box.toggle
        }

        states: [
            State {
                name: "topLeft"
                when: !box.toggle

                PropertyChanges {
                    target: box
                    color: "red"
                    x: 10
                    y: 10
                    rotation: 0
                }
            },
            State {
                name: "bottomRight"
                when: box.toggle

                PropertyChanges {
                    target: box
                    color: "teal"
                    x: root.width - box.width - 10
                    y: root.height - box.height - 10
                    rotation: 360
                }
            }
        ]

        transitions: Transition {
            SequentialAnimation {
                ColorAnimation { duration: 500 }
                RotationAnimation { duration: 500 }
                NumberAnimation { properties: "x"; duration: 500 }
                NumberAnimation { properties: "y"; duration: 500 }
                NumberAnimation { properties: "rotation"; duration: 500 }
            }
        }
    }
}

NumberAnimation could also be combined to move the Rectangle in x and y at the same time.

NumberAnimation { properties: "x"; duration: 500 }
NumberAnimation { properties: "y"; duration: 500 }

to

NumberAnimation { properties: "x,y"; duration: 500 }
0
Stephen Quan On

Did you know that you can assign animations directly to an event? To cover both forward and backward conditions I use two MouseAreas respectively. In the below MouseArea.onClicked events:

  • I was able to decide which bits are SequentialAnimation and which bits are ParallelAnimation
  • I was able to change the rotation from clockwise to anti-clockwise depending on which event was firing
  • I was able to optimize the backward animation since both "x,y" go to 10

I think you'll find this approach more succinct and more customizable than when the animations were inside Behaviors.

import QtQuick
import QtQuick.Controls
Page {
    title: "MouseArea.onClicked animations"
    Rectangle {
        id: root
        width:196
        height:196
        color:"lightgray"
        
        Rectangle {
            id: box
            width:48
            height:48
            x:10
            y:10
            color: "red"
            rotation:0
            
            MouseArea {
                id: forwards
                anchors.fill: parent
                enabled: box.x === 10
                onClicked: SequentialAnimation {
                    ParallelAnimation {
                        NumberAnimation { target: box; property: "x"; to: root.width - box.width - 10; duration: 500 }
                        NumberAnimation { target: box; property: "y"; to: root.height - box.height - 10; duration: 500 }
                    }
                    RotationAnimation { target: box; property: "rotation"; from: 0; to: 360; duration: 500 }
                    ColorAnimation { target: box; property: "color"; from: "teal"; to: "red"; duration: 500 }
                }
            }
            
            MouseArea {
                id: backwards
                anchors.fill: parent
                enabled: box.x !== 10
                onClicked: SequentialAnimation {
                    NumberAnimation { target: box; properties: "x,y"; to: 10; duration: 500 }
                    RotationAnimation { target: box; property: "rotation"; from: 360; to: 0; duration: 500 }
                    ColorAnimation { target: box; property: "color"; from: "teal"; to: "red"; duration: 500 }
                }
            } 
        }
    }
}

You can Try it Online!