Transition in child component binded to parent's animated property
-
Hello,
I have a problem in applying some animated state change for both parent and child elements.
Basically, the idea is to have some content that changes it's layout based on whether it is in one of the two states - "expanded" and "" (not expanded, default one).
The idea is to have both those states defined in parent and child elements with some custom (and different) transitions. Those transitions are used to rearrange the contents of the child element based on the state of the parent.
The problem is that a transition in the child element is not aware of the parent's transition, and when state change is triggered, it uses the parent's properties that was in an old state, thus causing wrong and abrupt animations in child element.
Consider following example. The main.qml file instantiates some big black rectangle that will serve in this example as the parent with two states ("rectParent")
import QtQuick 2.9 import QtQuick.Window 2.2 import QtQuick.Controls 2.2 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") Button{ anchors.bottom: parent.bottom anchors.right: parent.right text: qsTr("Animation") font.family: "Ubuntu" font.pixelSize: 24 onClicked: rectParent.state = rectParent.state === "expanded"? "" : "expanded" } Rectangle { // Parent rectangle id: rectParent anchors.top: parent.top anchors.left: parent.left height: parent.height/2 width: parent.width/2 color: "black" // States for parent rectangle states: [ State { name: "expanded" PropertyChanges { target: rectParent; height: parent.height; } } ] // Transitions for parent Rectangle transitions: [ Transition { from: "*"; to: "expanded" PropertyAnimation { target: rectParent; property: "height"; duration: 2000; easing.type: Easing.InOutCirc; } }, Transition { from: "expanded"; to: "*" PropertyAnimation { target: rectParent; property: "height"; duration: 2000; easing.type: Easing.InOutCirc; } } ] // Inner content Rectangle { id: cont1 color: "yellow" anchors.left: parent.left anchors.top: parent.top anchors.margins: 25 height: parent.height*2/3 width: parent.width*2/3 CustomComponent { expanded: rectParent.state } } } }
The code for some custom child component (CustomComponent.qml) is as follows:
import QtQuick 2.9 import QtQuick.Window 2.2 import QtQuick.Controls 2.2 Item { id: root anchors.fill: parent property bool expanded: false state: expanded? "expanded" : "" // Contents of the component Rectangle { id: rec1 color: "red" anchors.left: parent.left anchors.top: parent.top anchors.margins: 25 width: parent.width/5 height: parent.height/4 } Rectangle { id: rec2 color: "green" anchors.left: rec1.right anchors.top: parent.top anchors.margins: 25 width: parent.width/5 height: parent.height/4 } Rectangle { id: rec3 color: "blue" anchors.left: rec2.right anchors.top: parent.top anchors.margins: 25 width: parent.width/5 height: parent.height/4 } // States for parent rectangle states: [ State { name: "expanded" PropertyChanges { target: rec1; height: parent.height; } PropertyChanges { target: rec2; height: parent.height; } PropertyChanges { target: rec3; height: parent.height; } } ] // Transitions for parent Rectangle transitions: [ Transition { from: "*"; to: "expanded" PropertyAnimation { target: rec1; property: "height"; duration: 2000; easing.type: Easing.InOutCirc; } PropertyAnimation { target: rec2; property: "height"; duration: 2000; easing.type: Easing.InOutCirc; } PropertyAnimation { target: rec3; property: "height"; duration: 2000; easing.type: Easing.InOutCirc; } }, Transition { from: "expanded"; to: "*" PropertyAnimation { target: rec1; property: "height"; duration: 2000; easing.type: Easing.InOutCirc; } PropertyAnimation { target: rec2; property: "height"; duration: 2000; easing.type: Easing.InOutCirc; } PropertyAnimation { target: rec3; property: "height"; duration: 2000; easing.type: Easing.InOutCirc; } } ] }
In this particular example, the problem will be that transition in the CustomComponent element is launched at the moment when the parent height property is still from the old state, and this value is used as target value for animation. Then, when animation is finished, the value is abruptly changed to the new parent.height from the new state. This is a working example so the problem can be easily visualized.
I think that it would be really nice to have such a nested components that can rearrange their contents based on some state flag, while also following any animations in the parent element.
Am I doing something wrong with the general pattern, or there is some workaround on this?