Reputation: 121
When I try to display data through a ListView
, everytime the model is updated the view returns to the beginning.
Is there a way to make ListView
handle the model updates without changing the visibleArea
of the inner Flickable
(or changing it in a reasonable way)?
Ideally, the same area should remain visible.
Here a minimal example where you can see that behaviour: if you scroll down in flickable
(on the left) and in listView
(on the right), when the timer is triggered the first one will stay where you left it, the second one will go back to beginning.
QML online live example
import QtQuick 2.15
Rectangle {
id:root
property int model: 10
property int delegateHeight: height/10*0.8
property int delegateSpacing: height/10*0.2
color: "#afafaf"
anchors.fill: parent
Timer {
interval: 5000
repeat: true
running: true
onTriggered: root.model++
}
Flickable {
id: flickable
x: 0
y: 0
width: parent.width/2
height: parent.height
clip: true
contentHeight: root.delegateHeight*repeater.count
Repeater {
id: repeater
model: root.model
delegate: Rectangle {
x: 0
y: (root.delegateHeight+root.delegateSpacing)*index
width: flickable.width
height: root.delegateHeight
color: "#abcdef"
Text {
text: index+1
}
}
}
}
ListView {
id: listView
x: parent.width/2
y: 0
width: parent.width/2
height: parent.height
clip: true
model: root.model
spacing: root.delegateSpacing
delegate: Rectangle {
width: ListView.view.width
height: root.delegateHeight
color: "#fedcba"
Text {
text: index+1
}
}
}
}
EDIT: I found a sort of workaround, but I don't think it's the right way to go.
Adding to listView
something like this, will keep the visibleArea
position on model increasing, but will probably have some drawback when decreasing the counter.
property real lastY: 0
onContentYChanged: {
if(!moving){
listView.contentY = listView.lastY+listView.originY
}
listView.lastY = listView.contentY-listView.originY
}
Upvotes: 4
Views: 1107
Reputation: 121
I've adapted the workaround presented to handle also the shrink case.
Basically, every time the user moves the content, the component stores the new position.
When the content moves by itself, like for a change in the model, the component restores the last position setted by the user, avoiding placing it outside the view.
To achieve this behavior something like this should be a added to ListView
:
property real lastY: 0
onContentYChanged: {
if (!moving) {
listView.contentY = Math.max(0, Math.min(listView.lastY, listView.contentHeight-listView.height))+listView.originY
}
listView.lastY = listView.contentY-listView.originY
}
Working reviewed example here.
There is probably still room for some improvement, but for the moment this mechanism satisfies my needs.
Upvotes: 3