Following this Qt tutorial I have written this simple code. There is a horizontal ListView
with some simple colored rectangle on it as delegate for the model items.
import QtQuick 2.5
import QtQuick.Window 2.0
import QtQml.Models 2.2
Window {
visible: true
width: 300
height: 120
title: qsTr("Hello World")
Rectangle {
anchors.fill: parent;
ListView{
id: timeline
anchors.fill: parent
orientation: ListView.Horizontal
model: visualModel
delegate: timelineDelegate
moveDisplaced: Transition {
NumberAnimation{
properties: "x,y"
duration: 200
}
}
DelegateModel {
id: visualModel
model: timelineModel
delegate: timelineDelegate
}
Component {
id: timelineDelegate
MouseArea {
id: dragArea
width: 100; height: 100
property bool held: false
drag.target: held ? content : undefined
drag.axis: Drag.XAxis
onPressAndHold: held = true
onReleased: held = false
Rectangle {
id: content
anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter }
width: 100
height: 100
color: colore
opacity: dragArea.held ? 0.8 : 1.0
Drag.active: dragArea.held
Drag.source: dragArea
Drag.hotSpot.x: width / 2
Drag.hotSpot.y: height / 2
states: State{
when: dragArea.held
ParentChange { target: content; parent: timeline }
AnchorChanges {
target: content
anchors { horizontalCenter: undefined; verticalCenter: undefined }
}
}
}
DropArea {
anchors.fill: parent
onEntered: {
visualModel.items.move( drag.source.DelegateModel.itemsIndex, dragArea.DelegateModel.itemsIndex)
timeline.currentIndex = dragArea.DelegateModel.itemsIndex
}
}
}
}
ListModel {
id: timelineModel
// @disable-check M16
ListElement { colore: "blue" }
// @disable-check M16
ListElement { colore: "orange" }
// @disable-check M16
ListElement { colore: "red" }
// @disable-check M16
ListElement { colore: "yellow" }
// @disable-check M16
ListElement { colore: "green" }
// @disable-check M16
ListElement { colore: "yellow" }
// @disable-check M16
ListElement { colore: "red" }
// @disable-check M16
ListElement { colore: "blue" }
// @disable-check M16
ListElement { colore: "green" }
}
}
}
}
If I press and hold on an Item
, I can swap it with the other with a nice moving effect.
The problem starts when there are a lot of items on the list and the target position is beyond the visible items. I can drag the item ad move it near the right or left border... here the moving effect is absolutely not nice.
Is there a best practice for scrolling correctly the list when an item arrives near the border?
I would like the scrolling starts before the item touches the border!
The nice one
The bad one
ListView
scrolls when ListView.currentIndex
is changed. That is, the last line in the drop area:
timeline.currentIndex = dragArea.DelegateModel.itemsIndex
says current index, which is always visible, is the dragged item. However if the dragged item arrives border, user expects to see not only the dragged item but also the item next to it. Therefore you need to add one more item to currentIndex
:
timeline.currentIndex = dragArea.DelegateModel.itemsIndex + 1
and now list view properly scrolls to right if you drag an item to the right border. To make it avaliable in both left and right border, we need to add a little math to it:
MouseArea {
id: dragArea
property int lastX: 0
property bool moveRight: false
onXChanged: {
moveRight = lastX < x;
lastX = x;
}
//....
DropArea {
anchors.fill: parent
onEntered: {
visualModel.items.move( drag.source.DelegateModel.itemsIndex,
dragArea.DelegateModel.itemsIndex)
if (dragArea.moveRight)
timeline.currentIndex = dragArea.DelegateModel.itemsIndex + 1
else
timeline.currentIndex = dragArea.DelegateModel.itemsIndex - 1
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With