QMLの状態変化とアニメーション効果

QML State and Animation
QMLアイテムにアニメーション効果を適用したい場合は、transitionsプロパティを使用します。

Transitionを定義する前に、アニメーション後の状態を示すコードを用意します。この状態はstatesプロパティーで記述し、State.nameで指定した名称をアイテムのstateプロパティに代入すると、State内の定義がアイテムに反映されるようになります。アイテムのステータスの変更を検知したいのであれば「onStateChanged」関数を組み込みます。

Stateに定義できものとして、アンカーを変更する「AnchorChanges」、アイテムの親子関係を変更する「ParentChange」、アイテムのプロパティを変更する「PropertyChanges」が挙げられます。

Stateによるプロパティ値の変更例を紹介します。このQMLコードでは、ボタンを押すと「lblColor.state」が「red」に設定されます。これによりラベルのstatesにある「red」を名称に持つデータが適用されるため、lblColorをターゲットにcolorプロパティが"red"になります。なお、「target:this」と記述してしまうとStateアイテムを参照することになるため、この方法は使えません。
state.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.0

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("State test")

    ColumnLayout{
        Label{
            id: lblColor
            text: "Hello!"
            state: "black"
            states:[
                State{
                    name:"black"
                    PropertyChanges{
                        target:lblColor
                        color:"black"
                    }
                },
                State{
                    name:"red"
                    PropertyChanges{
                        target:lblColor
                        color:"red"
                    }
                }
            ]
        }

        Button{
            text: "Change"
            onClicked: {
                lblColor.state = "red";
            }
        }
    }
}
Stateにある「when」プロパティがtrueであるときは、そのステータスが自動で適用されます。つまり、whenに条件式を割り当てれば、シグナルを調べる必要がなくなるというわけです。
when.qml
MouseArea{
    id:ma
    states:[
        State{
            // このマウスエリアが押されると、rcというアイテムが表示される
            when: ma.pressed
            PropertyChanges {
                target: rc
                visible: true
            }
        }
    ]
}
アイテムのtransitionsプロパティ内に記述することで、stateをキーにしたアニメーションを実行できます。

この例では、ラベルのステートが"black"から"red"に切り替わった時に、ColorAnimationが実行されるので、1秒かけて文字の色が黒から赤に変わっていきます。
color.qml
Label{
    id: lblColor
    text: "Hello!"
    state: "black"
    states:[
        State{
            name:"black"
            PropertyChanges{
                target:lblColor
                color:"black"
            }
        },
        State{
            name:"red"
            PropertyChanges{
                target:lblColor
                color:"red"
            }
        }
    ]
    transitions: [
        Transition {
            from: "black"
            to: "red"
            ColorAnimation {
                target:lblColor
                duration: 1000
            }
        }
    ]
}
transitionsは配列なので、状態値の変化の数だけTransitionを追加できます。また、fromを明示しない場合は、変化前のstateはすべての値が対象になります。toも同様です。

次にアイテムのプロパティ値を徐々に変化させることでアニメーションさせる「PropertyAnimation」について解説します。このデータの「property」に指定したプロパティ文字列(クォーテーションで囲まないとそのプロパティの数値が参照されてしまうため動作しない)を「from(未指定の場合は現時点のアイテムが持つ値)」から「to」へとdurationミリ秒をかけて変化していきます。easingプロパティによるイージングも実装できます。
move.qml
ColumnLayout{
    Label{
        id: lblColor
        /* 省略 */
        transitions: [
            Transition {
                from: "black"
                to: "red"
                ColorAnimation {
                    target:lblColor
                    duration: 1000
                }
            },
            Transition{
                to: "move"
                PropertyAnimation {
                    target: lblColor
                    // 複数のターゲットを指定したい場合の例
                    // targets:[lblColor, lblExtra]
                    easing.type: Easing.InOutQuad
                    to: 200
                    duration: 2000
                    property: "x"
                    // 複数のプロパティを同時に変更したい場合の例
                    // properties: "x,y"
                    to: 200
                }
            }
        ]
    }

    Button{
        text: "Color"
        onClicked: {
            lblColor.state = "red";
        }
    }

    Button{
        text: "Move"
        onClicked: {
            lblColor.state = "move";
        }
    }
}
このコードでは「Move」ボタンを押すとラベルのステートが「move」になり、かつfromステートが未指定なので、ラベルの状態(stateがblackかredであるか)に関わらず、ラベルが右方向に200ピクセル移動します。

対象のプロパティが数値型であれば、PropertyAnimationの代わりにNumberAnimationを使うことができます。基本的な動作は変わりありませんが、数値に特化した分、処理は高速です。
number.qml
Transition{
    to: "move"
    NumberAnimation {
        target: lblColor
        property: "x"
        easing.type: Easing.InOutQuad
        to: 200
        duration: 2000
    }
}
2018/10/30