ListView: position delegate items at zero on the inactive axis
FxListItemSG::setPosition() only cares about a single axis, which is based on the current orientation. If the orientation is Vertical, then the y axis will be used with positioning the delegate item, and if the orientation is Horizontal, then the x axis will be used instead. This would cause problems when the ListView is changing its orientation. Because if the ListView's orientation suddently changes from Vertical to Horizontal, then all the delegate items will keep their old y value, which FxListItemSG::setPosition() won't do anything about since the new "active" axis is now the x axis. This patch fixes the issue by resetting the value for the "inactive" axis back to zero, in pointForPosition() which is used by FxListItemSG::setPosition(). The problem wasn't noticeable when using a normal QQmlDelegateModel, since the delegate items would be created lazily when they needed to appear inside the viewport, at which point they'd be given the correct x and y values. (The position is first (0, 0), and then layoutVisibleItems will updated one of those values based on the orientation). But if the user decides to use a QQmlObjectModel based model instead, then the delegate items would all be created immediately with a persistent lifetime, which would never have their position reset as a natural result of the item view delegate lifecycle mechanism. Fixes: QTBUG-115696 Change-Id: I5377aeb556be2f536794f489b8232c5b9675ab78 Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> (cherry picked from commitf03a9839b6
) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit27beeb7ccb
)
This commit is contained in:
parent
150eae8cde
commit
a4cc75c3bf
|
@ -326,21 +326,21 @@ private:
|
|||
if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) {
|
||||
if (section())
|
||||
pos += section()->height();
|
||||
return QPointF(itemX(), -itemHeight() - pos);
|
||||
return QPointF(0, -itemHeight() - pos);
|
||||
} else {
|
||||
if (section())
|
||||
pos += section()->height();
|
||||
return QPointF(itemX(), pos);
|
||||
return QPointF(0, pos);
|
||||
}
|
||||
} else {
|
||||
if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
|
||||
if (section())
|
||||
pos += section()->width();
|
||||
return QPointF(-itemWidth() - pos, itemY());
|
||||
return QPointF(-itemWidth() - pos, 0);
|
||||
} else {
|
||||
if (section())
|
||||
pos += section()->width();
|
||||
return QPointF(pos, itemY());
|
||||
return QPointF(pos, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
import QtQuick
|
||||
|
||||
ListView {
|
||||
id: root
|
||||
|
||||
function allDelegates(valueSelector) {
|
||||
let sum = 0;
|
||||
for (let i = 0; i < root.count; i++)
|
||||
sum += valueSelector(root.itemAtIndex(i));
|
||||
return sum;
|
||||
}
|
||||
|
||||
readonly property bool isXReset: allDelegates(function(item) { return item?.x ?? 0; }) === 0
|
||||
readonly property bool isYReset: allDelegates(function(item) { return item?.y ?? 0; }) === 0
|
||||
|
||||
width: 500
|
||||
height: 500
|
||||
delegate: Rectangle {
|
||||
width: root.width
|
||||
height: root.height
|
||||
color: c
|
||||
}
|
||||
model: ListModel {
|
||||
ListElement {
|
||||
c: "red"
|
||||
}
|
||||
ListElement {
|
||||
c: "green"
|
||||
}
|
||||
ListElement {
|
||||
c: "blue"
|
||||
}
|
||||
ListElement {
|
||||
c: "cyan"
|
||||
}
|
||||
ListElement {
|
||||
c: "magenta"
|
||||
}
|
||||
ListElement {
|
||||
c: "teal"
|
||||
}
|
||||
}
|
||||
clip: true
|
||||
orientation: ListView.Vertical
|
||||
snapMode: ListView.SnapOneItem
|
||||
highlightRangeMode: ListView.StrictlyEnforceRange
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
import QtQuick
|
||||
|
||||
ListView {
|
||||
id: root
|
||||
|
||||
readonly property bool isXReset: red.x === 0 && green.x === 0 && blue.x === 0 && cyan.x === 0 && magenta.x === 0 && teal.x === 0
|
||||
|
||||
readonly property bool isYReset: red.y === 0 && green.y === 0 && blue.y === 0 && cyan.y === 0 && magenta.y === 0 && teal.y === 0
|
||||
|
||||
width: 500
|
||||
height: 500
|
||||
model: ObjectModel {
|
||||
Rectangle {
|
||||
id: red
|
||||
width: root.width
|
||||
height: root.height
|
||||
color: "red"
|
||||
}
|
||||
Rectangle {
|
||||
id: green
|
||||
width: root.width
|
||||
height: root.height
|
||||
color: "green"
|
||||
}
|
||||
Rectangle {
|
||||
id: blue
|
||||
width: root.width
|
||||
height: root.height
|
||||
color: "blue"
|
||||
}
|
||||
Rectangle {
|
||||
id: cyan
|
||||
width: root.width
|
||||
height: root.height
|
||||
color: "cyan"
|
||||
}
|
||||
Rectangle {
|
||||
id: magenta
|
||||
width: root.width
|
||||
height: root.height
|
||||
color: "magenta"
|
||||
}
|
||||
Rectangle {
|
||||
id: teal
|
||||
width: root.width
|
||||
height: root.height
|
||||
color: "teal"
|
||||
}
|
||||
}
|
||||
clip: true
|
||||
orientation: ListView.Vertical
|
||||
snapMode: ListView.SnapOneItem
|
||||
highlightRangeMode: ListView.StrictlyEnforceRange
|
||||
}
|
|
@ -60,6 +60,9 @@ private slots:
|
|||
void fetchMore_data();
|
||||
void fetchMore();
|
||||
|
||||
void changingOrientationResetsPreviousAxisValues_data();
|
||||
void changingOrientationResetsPreviousAxisValues();
|
||||
|
||||
private:
|
||||
void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to);
|
||||
QScopedPointer<QPointingDevice> touchDevice = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
|
||||
|
@ -1116,6 +1119,40 @@ void tst_QQuickListView2::fetchMore() // QTBUG-95107
|
|||
QCOMPARE_GE(model.m_lines, listView->count()); // fetchMore() was called
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QQuickListView2::changingOrientationResetsPreviousAxisValues_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("sourceFile");
|
||||
QTest::newRow("ObjectModel") << QByteArray("changingOrientationWithObjectModel.qml");
|
||||
QTest::newRow("ListModel") << QByteArray("changingOrientationWithListModel.qml");
|
||||
}
|
||||
|
||||
void tst_QQuickListView2::changingOrientationResetsPreviousAxisValues() // QTBUG-115696
|
||||
{
|
||||
QFETCH(QByteArray, sourceFile);
|
||||
|
||||
QQuickView window;
|
||||
QVERIFY(QQuickTest::showView(window, testFileUrl(QString::fromLatin1(sourceFile))));
|
||||
auto *listView = qobject_cast<QQuickListView *>(window.rootObject());
|
||||
QVERIFY(listView);
|
||||
|
||||
// Starts of with vertical orientation. X should be 0 for all delegates, but not Y.
|
||||
QVERIFY(listView->property("isXReset").toBool());
|
||||
QVERIFY(!listView->property("isYReset").toBool());
|
||||
|
||||
listView->setOrientation(QQuickListView::Orientation::Horizontal);
|
||||
|
||||
// Y should be 0 for all delegates, but not X.
|
||||
QVERIFY(!listView->property("isXReset").toBool());
|
||||
QVERIFY(listView->property("isYReset").toBool());
|
||||
|
||||
listView->setOrientation(QQuickListView::Orientation::Vertical);
|
||||
|
||||
// X should be 0 for all delegates, but not Y.
|
||||
QVERIFY(listView->property("isXReset").toBool());
|
||||
QVERIFY(!listView->property("isYReset").toBool());
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QQuickListView2)
|
||||
|
||||
#include "tst_qquicklistview2.moc"
|
||||
|
|
Loading…
Reference in New Issue