[Qt-qml] Section header 'always on top'
tapani.mikola at nokia.com
tapani.mikola at nokia.com
Fri Aug 13 10:10:25 CEST 2010
Hi,
Wanted to share one exciting (at least IMO) piece of code.
Some existing devices have this fancy visual feature that when scrolling
a list the section header stays on top and only when the next section
header scrolls in it 'pushes' the old one away. (See the attached picture)
Unfortunately QML in Qt 4.7 does not support that kind of property for
ListView. Section headers always scroll along with the list items. But
no worries, as the following example (extended from the ListView
documentation example) does the trick. Hopefully the comments in line
the code are enough for documentation. Post any comments or questions to
this list.
As continuation, I am planning to create a couple of JIRA items:
* To have a section.alwaysOnTop -property (or something similar) for
ListView (the below trick wouldn't be needed at all)
* To have a 'ListView.previousSection et al' attached properties
available also to the section delegate (currently only available for
item delegate). These would make these kind of things easier to do. Now
the code has to refer to list & model through their id:s
First a component to draw the section header:
---- Code snippet starts <SectionHeader.qml> ----
import Qt 4.7
Rectangle {
color: "lightsteelblue"
height: childrenRect.height
property alias text: hdrText.text
opacity: 0.85
Text {
id: hdrText
font.bold: true
font.pixelSize:26
}
}
---- Code snippet ends <SectionHeader.qml> ----
and then the main qml file:
--- Code snippet starts <alwaysonsectionheader.qml> ----
import Qt 4.7
Rectangle {
id: container
width: 200
height: 250
gradient: Gradient {
GradientStop { position: 0.0; color: "#555555" }
GradientStop { position: 1.0; color: "#eeeeee" }
}
Rectangle {
x: 180
width: 20
height: parent.height
gradient: Gradient {
GradientStop { position: 0.0; color: "#eeeeee" }
GradientStop { position: 1.0; color: "#555555" }
}
}
ListModel {
id: animalsModel
ListElement { name: "Parrot"; size: "Small" }
ListElement { name: "Guinea pig"; size: "Small" }
ListElement { name: "Mouse"; size: "Small" }
ListElement { name: "Sparrow"; size: "Small" }
ListElement { name: "Dog"; size: "Medium" }
ListElement { name: "Cat"; size: "Medium" }
ListElement { name: "Dolphin"; size: "Medium" }
ListElement { name: "Seal"; size: "Medium" }
ListElement { name: "Elephant"; size: "Large" }
ListElement { name: "Blue whale"; size: "Large" }
ListElement { name: "Rhino"; size: "Large" }
ListElement { name: "Ostrich"; size: "Large" }
ListElement { name: "Sperm whale"; size: "Large" }
ListElement { name: "Giraffe"; size: "Large" }
}
// The section header delegate
Component {
id: sectionDelegate
Item {
id: sectionItem
height: childrenRect.height
property real myPos: y - animalsList.contentY
// For some reason, this does not work
//visible: myPos >= 0
// The visible -property setting(s) below are needed only,
if SectionHeader has transparency (opacity < 1.0)
onMyPosChanged: {
if (animalsList.contentY >= 0) {
if (myPos < height*2 && myPos > -height*2) {
// In the 'hot' area
// Set the correct text.
if (myPos < 0) {
sectionHeader.text = section
visible = false
}
else {
// Oooh, would it be nice to have
'previousSection' property
// One can do this, if there is a
cacheBuffer for the list, if not I sometimes get undefined from get() as
// the listitem above the section header
is already deleted
//sectionHeader.text = y >= 1 ?
animalsModel.get(animalsList.indexAt(0, y-1)).size :
animalsModel.get(0).size
// Safer version that does not require
cacheBuffer for the animalsList
var nextIndex = animalsList.indexAt(0,
y+height+1)
sectionHeader.text = nextIndex >= 1 ?
animalsModel.get(nextIndex-1).size : animalsModel.get(0).size
visible = true
}
// Then set y of the section header overlay to
give an illusion of 'push'
if (myPos < height && myPos >= 0)
sectionHeader.y = 0 - (height - myPos) //
push the old header away -effect
else
sectionHeader.y = 0 // clean up after push
}
else visible = true
}
else visible = true
}
SectionHeader {
width: animalsList.width
text: section
}
}
}
Item {
anchors.fill: parent
ListView {
id: animalsList
anchors.fill: parent
model: animalsModel
delegate: Text { text: name; font.pixelSize: 24 }
section.property: "size"
section.criteria: ViewSection.FullString
section.delegate: sectionDelegate
}
// The section header item (rectangle+text overlayed on top of
the ListView)
SectionHeader {
id: sectionHeader
visible: !animalsList.atYBeginning // not wanted when list
is at beginning (list can bounce and the section delegate is at right place)
width: parent.width
text: animalsList.currentSection
}
}
}
---- Code snippet ends <alwaysonsectionheader.qml> ----
-------------- next part --------------
A non-text attachment was scrubbed...
Name: listviewsectiontrick.png
Type: image/png
Size: 13644 bytes
Desc: listviewsectiontrick.png
Url : http://lists.qt.nokia.com/pipermail/qt-qml/attachments/20100813/35d381fd/attachment.png
More information about the Qt-qml
mailing list