Can't get my ListView Scrollbehavior correct in my simple example
-
cross-posted from: https://stackoverflow.com/questions/57079018/qml-cant-get-my-listview-scrollbehavior-correct-in-my-simple-example
Its my first time to use ListView and i need to implement a decent scroll behavior for my application
it "works" but sometimes the animation behavior is a little bit strangeI've wrote a small QML example (runnable with qmlscene tool) to show my problem
Sample source code:
import QtQuick 2.2 import QtQuick.Window 2.5 Window { width: 500 height: 700 visible: true // my model ctrl is in C++ // faked it here with pure QML to simplify the example ListModel { id: cppModel // different size - item type depdendend (just const here) ListElement { name: "Item 1"; active: false; height: 50 } ListElement { name: "Item 2"; active: false; height: 100 } ListElement { name: "Item 3"; active: false; height: 150 } ListElement { name: "Item 4"; active: false; height: 200 } ListElement { name: "Item 5"; active: false; height: 250 } ListElement { name: "Item 6"; active: false; height: 300 } property int currentItemIndex: -1 function activate_item(index) { // auto deactivate all others for(var i = 0; i < rowCount(); i++) { var active = (index === i) get(i).active = active if(active) { currentItemIndex = i } } } } Component { id: listViewDelegate Rectangle { height: model.active ? model.height : 30 width: 600 color: "transparent" border {color: model.active ? "yellow" : "black"; width: 2} Behavior on height { NumberAnimation { easing.type: Easing.InCirc duration: 5000 } } Text { text: model.name; font.pixelSize: 24 } MouseArea { anchors.fill: parent onClicked: { cppModel.activate_item(model.index) } } } } Rectangle { width: 400 height: 600 border {color: "steelblue"; width: 2} ListView { id: myList anchors.fill: parent clip: true model: cppModel delegate: listViewDelegate header: Rectangle { width: parent.width; height: 50 border {color: "red"; width: 2} Text { anchors.centerIn: parent text: "Header" font.pixelSize: 32 } } highlightMoveDuration: 5000 highlightMoveVelocity: -1 highlightResizeDuration: 5000 highlightResizeVelocity: -1 preferredHighlightBegin: 0 preferredHighlightEnd: currentItem.height highlightRangeMode: ListView.StrictlyEnforceRange snapMode: ListView.SnapToItem currentIndex: -1 onMovementStarted: { // show header again highlightRangeMode = ListView.ApplyRange } onCurrentIndexChanged: { // highlight current highlightRangeMode = ListView.StrictlyEnforceRange } } Connections { target: cppModel onCurrentItemIndexChanged: { // change comming from C++ if ( myList.currentIndex !== cppModel.currentItemIndex ) { myList.currentIndex = cppModel.currentItemIndex } } } } }
first: the item that is activated should be scrolled to top (that works) seems ok, only the animation i get are a little strange
my 2 "bad" animation scenarios:
if you activate Item 1..6 downwards, starting with Item 3 the Item Text is moved too far up and then comes back, the up scrolling should always stop at the items top, no bouncing etc. - i've already tried to replace the highlighter but gives me no better result
if you open for example Item 6 and the scroll with mouse to Item 1 and activates item 1, the animation (seems to) first closes the Item 6 and then scrolls the list, better would be that the scrolling/and resize to the activated item 1 is prio and the closing animation of the former item does not block/stutter the item 1 animation
would be glad if someone could kick me in the right direction how to solve the animation problems
thanks
-
a played a while with the ListView options but can't get the animations right
so i've tried to implement my own list view like item - as an example how the animation would feelworking sample, with an fake c++ model, with the animations i want to see
import QtQuick 2.5 import QtQuick.Controls 2.5 import QtQuick.Window 2.5 Window { width: 500 height: 700 visible: true // my model ctrl is in C++ // faked it here with pure QML to simplify the example ListModel { id: cppModel // different size - item type depdendend (just const here) ListElement { name: "Item 1"; active: false; height: 100 } ListElement { name: "Item 2"; active: false; height: 150 } ListElement { name: "Item 3"; active: false; height: 200 } ListElement { name: "Item 4"; active: false; height: 250 } ListElement { name: "Item 5"; active: false; height: 300 } ListElement { name: "Item 6"; active: false; height: 350 } property int currentItemIndex: -1 function activate_item(index) { // auto deactivate all others for(var i = 0; i < rowCount(); i++) { var active = (index === i) get(i).active = active if(active) { currentItemIndex = i } } } function remove_item(index) { if(currentItemIndex === -1) { console.log("can remove not active item") return } remove(currentItemIndex); } function deactivate_current_item() { if(currentItemIndex === -1) { console.log("can remove not active item") return } get(currentItemIndex).active = false } } Column { Rectangle { width: 320 height: 480 border { width: 2; color: "steelblue" } Flickable { id: flickable clip: true anchors.fill: parent contentWidth: 320 contentHeight: 600 function goto_header() { contentY = 0 } Behavior on contentY { NumberAnimation { easing.type: Easing.OutCubic duration: 500 } } Rectangle { id: myList anchors.top: parent.top anchors.left: parent.left width: flickable.contentWidth height: flickable.contentHeight Column { Rectangle { id: header width: 320 height: 40 color: "red" border { width: 2; color: "black" } Text { text: "Header"} } Repeater { model: cppModel Rectangle { readonly property int reducedSize: 30 width: 320 height: model.active ? model.height : reducedSize border { width: 2; color: "black" } Text { text: model.name } MouseArea { anchors.fill: parent onClicked: { // find new list contentY // works also if item above is shrinking // but only if shrinked height is for all items the same var newContentY = (model.index * reducedSize) + header.height cppModel.activate_item(model.index) // scroll to this element flickable.contentY = newContentY } } Behavior on height { NumberAnimation { easing.type: Easing.OutCubic duration: 500 } } } } } } } } Rectangle { height: 100 width: 320 Row { Button { text: "Delete" onClicked: { console.log("Delete clicked") cppModel.remove_item(); flickable.goto_header(); } } Button { text: "Save" onClicked: { console.log("Save clicked") cppModel.deactivate_current_item() } } } } } }
Screenshot of the sample program