diff options
author | Michael Brasser <mbrasser@ford.com> | 2018-03-13 19:50:17 -0500 |
---|---|---|
committer | Michael Brasser <michael.brasser@live.com> | 2018-10-17 14:32:15 +0000 |
commit | 50924bd8557db9a398f3c1ccdd6996d968658b23 (patch) | |
tree | f48a98741f6863e0ccd9579735c0425c27434473 | |
parent | d973907f6e4aae492dfad3eaad6827ffdc49962b (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.cpp | 38 | ||||
-rw-r--r-- | tests/auto/quick/qquicklistview/data/sectionSnapping.qml | 49 | ||||
-rw-r--r-- | tests/auto/quick/qquicklistview/tst_qquicklistview.cpp | 58 |
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); |