Solved Expandible/Collapsible Pane with smooth Animation in QML
-
Hey devs, it is possible to expand/collapse a panel with an smooth animation when it becomes visible.
Example:
import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.3 import QtQuick.Controls.Material 2.2 ApplicationWindow { visible: true width: 640 height: 480 title: qsTr("Example") property var settings1Model: [ {"settingsName": qsTr("Settings 1.1")}, {"settingsName": qsTr("Settings 1.2")}, {"settingsName": qsTr("Settings 1.3")} ] property var settings2Model: [ {"settingsName": qsTr("Settings 2.1")}, {"settingsName": qsTr("Settings 2.2")}, {"settingsName": qsTr("Settings 2.3")}, {"settingsName": qsTr("Settings 2.4")}, {"settingsName": qsTr("Settings 2.5")} ] property var settings3Model: [ {"settingsName": qsTr("Settings 3.1")}, {"settingsName": qsTr("Settings 3.2")}, {"settingsName": qsTr("Settings 3.3")} ] Flickable { id: flickable anchors.fill: parent contentHeight: root.implicitHeight boundsBehavior: Flickable.OvershootBounds Pane { id: root anchors.fill: parent ColumnLayout { anchors.right: parent.right anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter Label { topPadding: 10 bottomPadding: 10 font.pixelSize: 20 Layout.fillWidth: true Layout.preferredWidth: 1 horizontalAlignment: Qt.AlignHCenter text: qsTr("Example") } Button { id: buttonListSettings1 Layout.fillWidth: true text: qsTr("Settings 1") onClicked: { paneSettings1List.visible ? paneSettings1List.visible = false : paneSettings1List.visible = true } } Pane { id: paneSettings1List visible: false Material.background: "lightblue" padding: 0 anchors.left: parent.left anchors.right: parent.right ColumnLayout { anchors.right: parent.right anchors.left: parent.left ListView { id: listSettings1 visible: true boundsBehavior: Flickable.OvershootBounds interactive: false focus: true clip: true Layout.fillWidth: true height: contentHeight model: settings1Model delegate: ItemDelegate { id: itemDelegateSettings1 text: " " height: settings1DataColumn.implicitHeight padding: 0 width: parent.width onClicked: { } ColumnLayout { id: settings1DataColumn parent: itemDelegateSettings1.contentItem anchors.left: parent.left anchors.right: parent.right anchors.leftMargin: 20 anchors.rightMargin: 20 RowLayout { spacing: 20 Layout.fillWidth: true Item { height: 30 } Label { text: modelData.settingsName wrapMode: Label.WordWrap } } } } ScrollIndicator.vertical: ScrollIndicator {} } } } Button { id: buttonListSettings2 Layout.fillWidth: true text: qsTr("Settings 2") onClicked: { paneSettings2List.visible ? paneSettings2List.visible = false : paneSettings2List.visible = true } } Pane { id: paneSettings2List visible: false Material.background: "lightblue" padding: 0 anchors.left: parent.left anchors.right: parent.right ColumnLayout { anchors.right: parent.right anchors.left: parent.left ListView { id: listSettings2 visible: true boundsBehavior: Flickable.OvershootBounds interactive: false focus: true clip: true Layout.fillWidth: true height: contentHeight model: settings2Model delegate: ItemDelegate { id: itemDelegateSettings2 text: " " height: settings2DataColumn.implicitHeight padding: 0 width: parent.width onClicked: { } ColumnLayout { id: settings2DataColumn parent: itemDelegateSettings2.contentItem anchors.left: parent.left anchors.right: parent.right anchors.leftMargin: 20 anchors.rightMargin: 20 RowLayout { spacing: 20 Layout.fillWidth: true Item { height: 30 } Label { text: modelData.settingsName wrapMode: Label.WordWrap } } } } ScrollIndicator.vertical: ScrollIndicator {} } } } Button { id: buttonListSettings3 Layout.fillWidth: true text: qsTr("Settings 3") onClicked: { paneSettings3List.visible ? paneSettings3List.visible = false : paneSettings3List.visible = true } } Pane { id: paneSettings3List visible: false Material.background: "lightblue" padding: 0 anchors.left: parent.left anchors.right: parent.right ColumnLayout { anchors.right: parent.right anchors.left: parent.left ListView { id: listSettings3 visible: true boundsBehavior: Flickable.OvershootBounds interactive: false focus: true clip: true Layout.fillWidth: true height: contentHeight model: settings3Model delegate: ItemDelegate { id: itemDelegateSettings3 text: " " height: settings3DataColumn.implicitHeight padding: 0 width: parent.width onClicked: { } ColumnLayout { id: settings3DataColumn parent: itemDelegateSettings3.contentItem anchors.left: parent.left anchors.right: parent.right anchors.leftMargin: 20 anchors.rightMargin: 20 RowLayout { spacing: 20 Layout.fillWidth: true Item { height: 30 } Label { text: modelData.settingsName wrapMode: Label.WordWrap } } } } ScrollIndicator.vertical: ScrollIndicator {} } } } } } ScrollIndicator.vertical: ScrollIndicator { } } }
At the moment, I clicked a Button and the list becomes visible fast and hard. Is there a way to do this a little bit smoother, maybe with a animation?
-
@Manu19 Can use states to handle item properties and perform animations
states:[
State{
name:"hidecontainer"
PropertyChanges {
target: rect
y:-500
opacity:0
}
},
State{
name:"showcontainer"
PropertyChanges {
target: rect
y:0
opacity:1
}
}
]transitions: [ Transition { to:"showcontainer" NumberAnimation { duration: 500 properties:"y,opacity" easing.type: Easing.OutCubic } } ,Transition { to:"hidecontainer" NumberAnimation { duration: 500 properties:"y,opacity" easing.type: Easing.InCubic } } ]
In the above code opacity and y has been modified from 0 to 1 and -500 to 0 which makes slide down from top.
Like wise can handle for any properties of the rectangle(500x500).In your use case display the list at y= -list height and then perform animation to y=0 which will make the list visible with a slide down animation.
-
@Arvindhan-Ponnusamy Thank you for your answer. Your example helps a little bit.
The animation works fine, but the problem is the Column Layout. When I click Settings 2, then the List becomes visible with animation, but the button "Settings 3" change the y-position very hard. It is possible to make this also smooth with animations? -
@Manu19 Yes this also can be performed with same approach.
Move settings 3 along with the list using states. -
I simplified your code a bit to make it more concise ( a single model instead of 3, and
Column
+Repeater
instead ofColumnLayout
+ListView
)import QtQuick 2.7 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.3 import QtQuick.Controls.Material 2.2 ApplicationWindow { visible: true width: 640 height: 480 title: qsTr("Example") property var settingsModel: [ { "title": "Settings 1", "settings": [ qsTr("Settings 1.1"), qsTr("Settings 1.2"), qsTr("Settings 1.3") ] }, { "title": "Settings 2", "settings": [ qsTr("Settings 2.1"), qsTr("Settings 2.2"), qsTr("Settings 2.3"), qsTr("Settings 2.4"), qsTr("Settings 2.5") ] }, { "title": "Settings 3", "settings": [ qsTr("Settings 3.1"), qsTr("Settings 3.2"), qsTr("Settings 3.3"), ] } ] Flickable { id: flickable anchors.fill: parent contentHeight: root.implicitHeight boundsBehavior: Flickable.OvershootBounds Pane { id: root anchors.fill: parent Column { anchors.right: parent.right anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter Label { anchors { left: parent.left; right: parent.right } topPadding: 10 bottomPadding: 10 font.pixelSize: 20 horizontalAlignment: Qt.AlignHCenter text: qsTr("Example") } Repeater { model: settingsModel delegate: Column { property bool showList: false anchors.left: parent.left anchors.right: parent.right Button { anchors.left: parent.left anchors.right: parent.right text: modelData.title onClicked: paneSettingsList.shown = !paneSettingsList.shown } Pane { id: paneSettingsList // ## relevant part ## property bool shown: false visible: height > 0 height: shown ? implicitHeight : 0 Behavior on height { NumberAnimation { easing.type: Easing.InOutQuad } } clip: true // ## relevant part ## Material.background: "lightblue" padding: 0 anchors.left: parent.left anchors.right: parent.right Column { anchors.right: parent.right anchors.left: parent.left Repeater { id: listSettings1 model: modelData.settings delegate: ItemDelegate { id: itemDelegateSettings1 text: modelData padding: 0 width: parent.width } } } } } } } } ScrollIndicator.vertical: ScrollIndicator { } } }
The relevant part is the one with the
Behavior
, where the height of aPane
is animated. -
@GrecKo Thank you very much, this is exactly what I want.
-
This post is deleted!