qtqmlqtquick2

Collapsible Panel in QML


I am trying to create a collapsible panel in QML. The issue that I am facing is when the rectangle's (id: settingsBox) height is 0: in this case I can still see the contained Label (id: texter). I want it so that when the user clicks the header, the rectangle height animates and then text appears.

How can I achieve that?

Rectangle {
    
    id: panel
    
    property int margin: 5
    property int minWidth: 200
    property int prefWidth: 300
    property int maxWidth: 500
    
    property int minHeight: 300
    property int prefHeight: 500
    property int maxHeight: 600
    
    property int minHeaderHeight: 30
    property int prefHeaderHeight: 50
    property int maxHeaderHeight: 50
    
    property int maxPanelHeight: 600
    property int duration: 50
    
    width: 500
    height: 500
    
    ColumnLayout {
        id: layout
        anchors.fill: parent
        
        HeaderButton {
            id: headerButton1
            height: prefHeight
            anchors.left: parent.left
            anchors.leftMargin: margin
            anchors.right: parent.right
            anchors.rightMargin: margin
            anchors.top: parent.top
            anchors.topMargin: margin
            
            Layout.fillWidth: true
            Layout.minimumWidth: minWidth
            Layout.preferredWidth: prefWidth
            Layout.maximumWidth: maxWidth
            
            Layout.fillHeight: true
            Layout.minimumHeight: minHeaderHeight
            Layout.preferredHeight: prefHeaderHeight
            Layout.maximumHeight: maxHeaderHeight
            
            onHeaderBtnClicked: {
                console.log("Settings Opened");
                if(settingsBox.height===maxPanelHeight) {
                    heightAnimationRevert.start();
                } else {
                    heightAnimation.start();
                }
            }
            
            PropertyAnimation {
                id: heightAnimation
                target: settingsBox
                property: "height";
                from: 0;
                to: maxPanelHeight;
                duration: duration;
                running: false;
                loops: 1;
            }
            
            PropertyAnimation {
                id: heightAnimationRevert
                target: settingsBox
                property: "height";
                from: maxPanelHeight;
                to: 0;
                duration: duration;
                running: false;
                loops: 1;
            }
        }
        
        Rectangle {
            id: settingsBox
            anchors.top: headerButton1.bottom
            anchors.right: parent.right
            anchors.leftMargin: margin
            anchors.left: parent.left
            anchors.rightMargin: margin
            width: prefWidth
            height: 0
            color: "lightgray"
            
            Label {
                id: texter
                visible: true
                text: qsTr("Hello World");
                font.pointSize: 11
                clip: false
                textFormat: Text.AutoText
                verticalAlignment: Text.AlignVCenter
                horizontalAlignment: Text.AlignHCenter
            }
        }
    }
}

Solution

  • I finally got the answer. It was to use Spliview and animate the height for each of the children in splitView. Spliview hides its chidren's content, even if the children's height is zero.

    The answer provided by @BaCaRoZzo is close to what I wanted, but we have take care of the heights and other issues ourselves, when stacking up multiple similar components.

    I provide the code for those in need. Thanks, @BaCaRoZzo for the answer. I will use the opacity attribute in some other place!

    Rectangle {
        id: rectangle2
        width: 500
        height: 600
    
        SplitView {
            anchors.fill: parent
            orientation: Qt.Vertical
    
            PropertyAnimation {
                id: heightAnimation
                target: rect1
                property: "height";
                from: 0;
                to: 400;
                duration: 500;
                running: false;
                loops: 1;
            }
    
            Rectangle {
                id: rect1
                height: 0
                Layout.maximumHeight: 400
                color: "blue"
    
                Text {
                    text: "View 1"
                    anchors.centerIn: parent
                }
            }
    
            Rectangle {
                id: rect2
                Layout.minimumHeight: 50
                Layout.fillHeight: true
                color: "lightgray"
                Text {
                    text: "View 2"
                    anchors.centerIn: parent
                }
            }
    
            Rectangle {
                id: rect3
                height: 200
                color: "lightgreen"
                Text {
                    text: "View 3"
                    anchors.centerIn: parent
                }
    
                MouseArea {
                    id: mouseArea1
                    x: 8
                    y: 5
                    width: 484
                    height: 187
    
                    onClicked: heightAnimation.start();
                }
            }
        }
    }
    

    (The last rectangle serves as the button)