I am having a very specific problem when using a ListView QML element in combination with its section properties.
I am using Qt 4.8.6, but I also have the same problem when I try to do this in Qt 5.3.1.
The following code can also be run on older versions of Qt by simply changing the import statement to
import QtQuick 1.0 (for <Qt 4.7.4)
or
import QtQuick 1.1 (For> = Qt 4.7.4)
Here is a usage example to demonstrate my problem:
import QtQuick 2.2 Rectangle { width: 800 height: 800 color: "black" property int pageNumber: 1 property int totalPages: Math.ceil(animalListView.contentHeight/animalListView.height) Text { x: 2 y: 90 color: "Orange" text: "Expected height: " + (animalListView.count*70 + (50*10)) font.pixelSize: 28 } Text { x: 2 y: 0 color: "Orange" text: "Actual ContentHeight: " + animalListView.contentHeight font.pixelSize: 28 } Text { x: 2 y: 30 color: "Orange" text: "Actual ChildrenRectHeight: " + animalListView.childrenRect.height font.pixelSize: 28 } Text { x: 2 y: 60 color: "Orange" text: "Total model items (minus sections): " + animalListView.count font.pixelSize: 28 } Rectangle { id: boundingRect width: 640 height: 500 x: 20 y: 200 radius: 10 border.width: 1 border.color: "green" color: "transparent" // The delegate for each section header Component { id: sectionHeaderDelegate Rectangle { width: parent.width height: 50 // this is the problem color: "transparent" Text { anchors.left: parent.left id: headerText text: section color: "red" } Rectangle { anchors.fill: parent border.color: "purple" border.width: 1 color: "transparent" } } } ListModel { id: animalsModel ListElement { name: "1Parrot"; size: "Small" } ListElement { name: "2Guinea pig"; size: "Small" } ListElement { name: "3Dog"; size: "Medium" } ListElement { name: "4Cat"; size: "Medium" } ListElement { name: "5Elephant"; size: "Medium" } ListElement { name: "6Parrot"; size: "Small" } ListElement { name: "7Guinea pig"; size: "Small" } ListElement { name: "8Dog"; size: "Medium" } ListElement { name: "9Cat"; size: "Medium" } ListElement { name: "10Elephant"; size: "Large" } ListElement { name: "11Parrot"; size: "Large" } ListElement { name: "12Guinea pig"; size: "Large" } ListElement { name: "13Dog"; size: "Large" } ListElement { name: "14Cat"; size: "Medium" } ListElement { name: "15Elephant"; size: "Large" } ListElement { name: "16Parrot"; size: "Small" } ListElement { name: "17Guinea pig"; size: "Small" } ListElement { name: "18Dog"; size: "Medium" } ListElement { name: "19Cat"; size: "Medium" } ListElement { name: "20Elephant"; size: "Large" } } ListView { id: animalListView anchors.fill: parent anchors.margins: 10 clip: true interactive: true flickableDirection: Flickable.VerticalFlick boundsBehavior: Flickable.StopAtBounds model: animalsModel delegate: Item { width: parent.width height: 70 Text { text: name color: "green" } Rectangle { anchors.fill: parent border.color: "yellow" border.width: 1 color: "transparent" } } section.property: "size" section.criteria: ViewSection.FullString section.delegate: sectionHeaderDelegate } } Rectangle { anchors.top: boundingRect.top anchors.left: boundingRect.right anchors.leftMargin: 20 width: 40 height: 40 color: "blue" MouseArea { anchors.fill: parent onClicked: { if (pageNumber > 1) { animalListView.contentY -= animalListView.height; animalListView.returnToBounds(); --pageNumber; } } } enabled: (!animalListView.atYBeginning) visible: !(animalListView.atYBeginning && animalListView.atYEnd) Text { anchors.centerIn: parent font.family: "Wingdings 3" font.pixelSize: 40 text: "Γ" // Up arrow } } Text { visible: totalPages > 1 anchors.left: boundingRect.right anchors.verticalCenter: boundingRect.verticalCenter width: 100 height: 20 font.pixelSize: 18 horizontalAlignment: Text.AlignHCenter color: "red" text: qsTr("%1 of %2").arg(pageNumber).arg(totalPages) } Rectangle { anchors.bottom: boundingRect.bottom anchors.left: boundingRect.right anchors.leftMargin: 20 width: 40 height: 40 color: "orange" MouseArea { anchors.fill: parent onClicked: { if (pageNumber < totalPages) { animalListView.contentY += animalListView.height; ++pageNumber; } } } enabled: (!animalListView.atYEnd) visible: !(animalListView.atYBeginning && animalListView.atYEnd) Text { anchors.centerIn: parent font.family: "Wingdings 3" font.pixelSize: 40 text: "Γ" // Down arrow } } }
I use ListView to display a list of animal models classified by size. To achieve this categorization in the view, I use the section.property, section.critiria, and section.delegate ListView properties implemented in the code above.
( Note : Please ignore the fact that the model I put in the ListView is not sorted, I understand that this will create a lot of duplicate category entries in the ListView. This is not relevant.)
When the number of models exceeds the visible area of ββthe ListView, I use the totalPages property to calculate the number of full ListView pages for navigation. The up and down arrows simply decrease and increase the content. ListView by ListView height respectively.
The problem is that the contentHeight from the ListView does not remain static, it dynamically changes and causes the calculation of the totalPages property incorrectly.
It is interesting to note that this behavior occurs if and only if I set the height for the sectionHeaderDelegate rectangle. If I comment on the height instruction (height: 50), the contentHeight from the ListView remains static, as expected - with the drawback that the section headers / categories are now on top of the model text, which is not at all useful.
So my question is: why does the contentHeight element of a QML ListView element dynamically change if and only if I use a delegate of a section whose height has been set to a non-zero value?
In addition, I left the following properties in the ListView for testing purposes, the ListView should be used with up / down arrows:
interactive: true flickableDirection: Flickable.VerticalFlick boundsBehavior: Flickable.StopAtBounds