aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brasser <mbrasser@ford.com>2018-03-13 19:50:17 -0500
committerMichael Brasser <michael.brasser@live.com>2018-10-17 14:32:15 +0000
commit50924bd8557db9a398f3c1ccdd6996d968658b23 (patch)
treef48a98741f6863e0ccd9579735c0425c27434473
parentd973907f6e4aae492dfad3eaad6827ffdc49962b (diff)
Improve interaction between snapping and sections
* Use velocity to prefer snapping in the active direction. * Calculate snap based on where the item is, rather than where the section is. Change-Id: I2531501dbe0a58f26f20bc3e719e435185e047a5 Task-number: QTBUG-67051 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
-rw-r--r--src/quick/items/qquicklistview.cpp38
-rw-r--r--tests/auto/quick/qquicklistview/data/sectionSnapping.qml49
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp58
3 files changed, 134 insertions, 11 deletions
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 540805ac28..908801ce1c 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -515,8 +515,8 @@ QString QQuickListViewPrivate::sectionAt(int modelIndex)
qreal QQuickListViewPrivate::snapPosAt(qreal pos)
{
- if (FxViewItem *snapItem = snapItemAt(pos))
- return snapItem->position();
+ if (FxListItemSG *snapItem = static_cast<FxListItemSG*>(snapItemAt(pos)))
+ return snapItem->itemPosition();
if (visibleItems.count()) {
qreal firstPos = (*visibleItems.constBegin())->position();
qreal endPos = (*(--visibleItems.constEnd()))->position();
@@ -530,22 +530,35 @@ qreal QQuickListViewPrivate::snapPosAt(qreal pos)
FxViewItem *QQuickListViewPrivate::snapItemAt(qreal pos)
{
+ const qreal velocity = orient == QQuickListView::Vertical ? vData.velocity : hData.velocity;
FxViewItem *snapItem = nullptr;
+ FxViewItem *prevItem = nullptr;
qreal prevItemSize = 0;
for (FxViewItem *item : qAsConst(visibleItems)) {
if (item->index == -1)
continue;
- qreal itemTop = item->position();
- if (highlight && itemTop >= pos && item->endPosition() <= pos + highlight->size())
+
+ const FxListItemSG *listItem = static_cast<FxListItemSG *>(item);
+ qreal itemTop = listItem->position();
+ qreal itemSize = listItem->size();
+ if (highlight && itemTop >= pos && listItem->endPosition() <= pos + highlight->size())
return item;
+ if (listItem->section() && velocity > 0) {
+ if (itemTop + listItem->sectionSize() / 2 >= pos && itemTop - prevItemSize / 2 < pos)
+ snapItem = prevItem;
+ itemTop = listItem->itemPosition();
+ itemSize = listItem->itemSize();
+ }
+
// Middle of item and spacing (i.e. the middle of the distance between this item and the next
- qreal halfwayToNextItem = itemTop + (item->size()+spacing) / 2;
+ qreal halfwayToNextItem = itemTop + (itemSize+spacing) / 2;
qreal halfwayToPrevItem = itemTop - (prevItemSize+spacing) / 2;
if (halfwayToNextItem >= pos && halfwayToPrevItem < pos)
snapItem = item;
- prevItemSize = item->size();
+ prevItemSize = listItem->itemSize();
+ prevItem = item;
}
return snapItem;
}
@@ -1530,15 +1543,15 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
pos = isContentFlowReversed() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart;
} else {
if (isContentFlowReversed())
- pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent);
+ pos = qMax(qMin(-static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size(), -maxExtent), -minExtent);
else
- pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent);
+ pos = qMax(qMin(static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart, -maxExtent), -minExtent);
}
} else if (bottomItem && isInBounds) {
if (isContentFlowReversed())
- pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent);
+ pos = qMax(qMin(-static_cast<FxListItemSG*>(bottomItem)->itemPosition() + highlightRangeEnd - size(), -maxExtent), -minExtent);
else
- pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent);
+ pos = qMax(qMin(static_cast<FxListItemSG*>(bottomItem)->itemPosition() - highlightRangeEnd, -maxExtent), -minExtent);
} else {
QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
return;
@@ -1568,7 +1581,10 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
timeline.reset(data.move);
if (viewPos != position()) {
if (fixupMode != Immediate) {
- timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
+ if (fixupMode == ExtentChanged && data.fixingUp)
+ timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::OutQuad), fixupDuration/2);
+ else
+ timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
data.fixingUp = true;
} else {
timeline.set(data.move, -viewPos);
diff --git a/tests/auto/quick/qquicklistview/data/sectionSnapping.qml b/tests/auto/quick/qquicklistview/data/sectionSnapping.qml
new file mode 100644
index 0000000000..2583cc0377
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/sectionSnapping.qml
@@ -0,0 +1,49 @@
+import QtQuick 2.0
+
+ListView {
+ width: 400
+ height: 400
+ preferredHighlightBegin: 100
+ preferredHighlightEnd: 100
+ highlightRangeMode: ListView.StrictlyEnforceRange
+
+ model: ListModel {
+ ListElement { section: "1" }
+ ListElement { section: "1" }
+ ListElement { section: "1" }
+ ListElement { section: "2" }
+ ListElement { section: "2" }
+ ListElement { section: "2" }
+ }
+
+ delegate: Rectangle {
+ width: parent.width
+ height: 50
+ color: index % 2 ? "lightsteelblue" : "steelblue"
+ Text {
+ anchors.centerIn: parent
+ color: "white"
+ text: model.index
+ }
+ }
+
+ section.property: "section"
+ section.delegate: Rectangle {
+ width: parent.width
+ height: 50
+ color: "green"
+ Text {
+ anchors.centerIn: parent
+ color: "white"
+ text: "section"
+ }
+ }
+
+ highlight: Rectangle {
+ y: 100
+ z: 100
+ width: parent.width
+ height: 50
+ color: "#80FF0000"
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index 2574eb9c6c..ae02352293 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -132,6 +132,8 @@ private slots:
void sectionPropertyChange();
void sectionDelegateChange();
void sectionsItemInsertion();
+ void sectionsSnap_data();
+ void sectionsSnap();
void cacheBuffer();
void positionViewAtBeginningEnd();
void positionViewAtIndex();
@@ -2667,6 +2669,62 @@ void tst_QQuickListView::sectionsItemInsertion()
}
}
+void tst_QQuickListView::sectionsSnap_data()
+{
+ QTest::addColumn<QQuickListView::SnapMode>("snapMode");
+ QTest::addColumn<QPoint>("point");
+ QTest::addColumn<int>("duration");
+
+ QTest::newRow("drag") << QQuickListView::NoSnap << QPoint(100, 45) << 500;
+ QTest::newRow("flick") << QQuickListView::SnapOneItem << QPoint(100, 75) << 50;
+}
+
+void tst_QQuickListView::sectionsSnap()
+{
+ QFETCH(QQuickListView::SnapMode, snapMode);
+ QFETCH(QPoint, point);
+ QFETCH(int, duration);
+
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("sectionSnapping.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject());
+ QTRY_VERIFY(listview != nullptr);
+ listview->setSnapMode(snapMode);
+
+ QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
+ QTRY_COMPARE(listview->currentIndex(), 0);
+ QCOMPARE(listview->contentY(), qreal(-50));
+
+ // move down
+ flick(window.data(), QPoint(100, 100), point, duration);
+ QTRY_VERIFY(!listview->isMovingVertically());
+ QCOMPARE(listview->contentY(), qreal(0));
+
+ flick(window.data(), QPoint(100, 100), point, duration);
+ QTRY_VERIFY(!listview->isMovingVertically());
+ QCOMPARE(listview->contentY(), qreal(50));
+
+ flick(window.data(), QPoint(100, 100), point, duration);
+ QTRY_VERIFY(!listview->isMovingVertically());
+ QCOMPARE(listview->contentY(), qreal(150));
+
+ // move back up
+ flick(window.data(), point, QPoint(100, 100), duration);
+ QTRY_VERIFY(!listview->isMovingVertically());
+ QCOMPARE(listview->contentY(), qreal(50));
+
+ flick(window.data(), point, QPoint(100, 100), duration);
+ QTRY_VERIFY(!listview->isMovingVertically());
+ QCOMPARE(listview->contentY(), qreal(0));
+
+ flick(window.data(), point, QPoint(100, 100), duration);
+ QTRY_VERIFY(!listview->isMovingVertically());
+ QCOMPARE(listview->contentY(), qreal(-50));
+}
+
void tst_QQuickListView::currentIndex_delayedItemCreation()
{
QFETCH(bool, setCurrentToZero);