Keep GridView element in front of others during animation
-
Hello, I'm trying to understand how to maintain an element of a GridView on top of others during a ParentAnimation. I think it's best explained with this snippet, which I beg you to try out:
@import QtQuick 2.2Item {
width: 400; height: 400
id: mainGridView {
id: grid
anchors.fill: parent
cellWidth: width / Math.sqrt(model)
cellHeight: height / Math.sqrt(model)model: 9
delegate: Rectangle {
id: rect
width: grid.cellWidth
height: grid.cellHeight
color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)Text {
anchors.centerIn: parent
text: "ABABAB"
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
}MouseArea {
anchors.fill: parent
onClicked:
{
if (rect.state != "fullScreen")
rect.state = "fullScreen";
else
rect.state = "";
}
}states: [
State {
name: "fullScreen"
ParentChange {
target: rect
parent: main
width: parent.width
height: parent.height
x: 0
y: 0
}
}
]transitions: [
Transition {
ParentAnimation {
NumberAnimation { properties: "x, y, width, height"; duration: 500; easing.type: Easing.InQuad }
}
}
]
}
}
}
@
In practice, I zoom the selected element by changing its parent so that it can extend beyond the cell boundaries. And the zooming-in animation works fine: the rectangle is always painted on top of the others.
When zooming back though, the first thing that happens is that the parent is changed back to the gridview, therefore the rectangle is painted above previous elements but below the successive ones (in fact, the 1st element, at the top left, is always painted below all other elements whereas the 9th element, at the bottom right, is always painted like I want during the zooming-out animation).How can I solve this problem? I came up with a solution but thinking in an imperative way, not in a declarative way like QML requires...
-
Here is one simple way to do it. I introduced a "current" property and declared that if the clicked item is current, its z-order is higher than the other rects. This will ensure that the clicked item is always at the top of the painting stack even when the item is reparented back into the grid.
@
Item {
width: 400; height: 400
id: main
property var current
GridView {
id: grid
anchors.fill: parent
cellWidth: width / Math.sqrt(model)
cellHeight: height / Math.sqrt(model)model: 9 delegate: Rectangle { id: rect width: grid.cellWidth height: grid.cellHeight color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1) z: rect === current ? 100 : 0 Text { anchors.centerIn: parent text: "ABABAB" wrapMode: Text.WrapAtWordBoundaryOrAnywhere } MouseArea { anchors.fill: parent onClicked: { current = rect if (rect.state != "fullScreen") rect.state = "fullScreen"; else rect.state = ""; } } states: [ State { name: "fullScreen" ParentChange { target: rect parent: main width: parent.width height: parent.height x: 0 y: 0 } } ] transitions: [ Transition { ParentAnimation { NumberAnimation { properties: "x, y, width, height"; duration: 500; easing.type: Easing.InQuad } } } ] } }
}
@ -
[quote author="Jens" date="1392024205"]Here is one simple way to do it. I introduced a "current" property and declared that if the clicked item is current, its z-order is higher than the other rects. This will ensure that the clicked item is always at the top of the painting stack even when the item is reparented back into the grid.
@
Item {
width: 400; height: 400
id: main
property var current
GridView {
id: grid
anchors.fill: parent
cellWidth: width / Math.sqrt(model)
cellHeight: height / Math.sqrt(model)model: 9 delegate: Rectangle { id: rect width: grid.cellWidth height: grid.cellHeight color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1) z: rect === current ? 100 : 0 Text { anchors.centerIn: parent text: "ABABAB" wrapMode: Text.WrapAtWordBoundaryOrAnywhere } MouseArea { anchors.fill: parent onClicked: { current = rect if (rect.state != "fullScreen") rect.state = "fullScreen"; else rect.state = ""; } } states: [ State { name: "fullScreen" ParentChange { target: rect parent: main width: parent.width height: parent.height x: 0 y: 0 } } ] transitions: [ Transition { ParentAnimation { NumberAnimation { properties: "x, y, width, height"; duration: 500; easing.type: Easing.InQuad } } } ] } }
}
@
[/quote]Thanks Jens, I had indeed previously tried to play with the z coordinate in my main app (the above is just a snippet that somehow follows the structure of the main app), more precisely by giving the Transition an id and setting, inside Rectangle rect, the following:
@z: transition.running ? 100 : 0@
This didn't work with my main app but indeed works with the simple example as well as your solution does.
Maybe the problem is due to the fact that the delegate in my app is actually a Flipable.Now, I just came up with the solution: I have to bind the flipable's z with this mechanism to get the result I want!
This code doesn't work:
@import QtQuick 2.2Item {
width: 400; height: 400
id: mainGridView {
id: grid
anchors.fill: parent
cellWidth: width / Math.sqrt(model)
cellHeight: height / Math.sqrt(model)model: 9
delegate: Flipable {
width: grid.cellWidth
height: grid.cellHeightfront: Rectangle {
id: rect
width: parent.width
height: parent.height
z: fullScreenTransition.running ? 100 : 0
color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1)Text { anchors.centerIn: parent text: "ABABAB" wrapMode: Text.WrapAtWordBoundaryOrAnywhere } MouseArea { anchors.fill: parent onClicked: { if (rect.state != "fullScreen") rect.state = "fullScreen"; else rect.state = ""; } } states: [ State { name: "fullScreen" ParentChange { target: rect parent: main width: parent.width height: parent.height x: 0 y: 0 } } ] transitions: [ Transition { id: fullScreenTransition ParentAnimation { NumberAnimation { properties: "x, y, width, height"; duration: 500; easing.type: Easing.InQuad } } } ]
}
}
}
}
@This code does!
@import QtQuick 2.2Item {
width: 400; height: 400
id: mainGridView {
id: grid
anchors.fill: parent
cellWidth: width / Math.sqrt(model)
cellHeight: height / Math.sqrt(model)model: 9
delegate: Flipable {
width: grid.cellWidth
height: grid.cellHeight
z: fullScreenTransition.running ? 100 : 0front: Rectangle {
id: rect
width: parent.width
height: parent.heightcolor: Qt.rgba(Math.random(), Math.random(), Math.random(), 1) Text { anchors.centerIn: parent text: "ABABAB" wrapMode: Text.WrapAtWordBoundaryOrAnywhere } MouseArea { anchors.fill: parent onClicked: { if (rect.state != "fullScreen") rect.state = "fullScreen"; else rect.state = ""; } } states: [ State { name: "fullScreen" ParentChange { target: rect parent: main width: parent.width height: parent.height x: 0 y: 0 } } ] transitions: [ Transition { id: fullScreenTransition ParentAnimation { NumberAnimation { properties: "x, y, width, height"; duration: 500; easing.type: Easing.InQuad } } } ]
}
}
}
}
@:))
-
It makes sense because z-values are only relevant when comparing items that have the same parent. Since Flippable are all direct children of the GridView, they are painted in order according to the z-value you have set on the Flippable itself.
When you assign the back or front properties of the Flippable itself, you are actually assigning a child of the flippable, and setting the z-value of a child has no effect on the painting order of its parent. Each node is also drawing all of its children before the next node is considered so the only thing you can effect by setting the z-value of the back item is which order you draw the back vs front Flippable items.
@
GridView
| |
Delegate1 Delegate2
| | | |
Back Front Back Front
@