Release section item when the corresponding view item removed
The section item has not been removed or added to the section cache in all cases when the corresponding delegate item has been moved out of the visible area, either during flick or scroll. This happens in a case where the delegate item has been requested to be removed (as it goes out of the visible area) from the list view, but it's not released from the delegate model due to its caching mechanism. When an item is outside the visible area, releaseItem() is triggered, intended to free the item and its sections. The problem arises when releaseItem() calls QQmlInstanceModel::release(), which caches the item in the delegate model, but does not free the section. This prevents the section item from being released properly. This patch releases the section item whenever removeItem is triggered from the list view, which happens when the delegate item is moved out of the visible area. Fixes: QTBUG-137172 Pick-to: 6.8 6.5 Change-Id: Ib7e78309e076e76750b03f3238a7501563a3962a Reviewed-by: Oliver Eftevaag <oliver.eftevaag@qt.io> (cherry picked from commit5a664f0836
) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commitd0287165a7
)
This commit is contained in:
parent
dd41fe2fae
commit
1b51dade3a
|
@ -806,6 +806,10 @@ void QQuickListViewPrivate::removeItem(FxViewItem *item)
|
|||
#endif
|
||||
{
|
||||
qCDebug(lcItemViewDelegateLifecycle) << "\treleasing stationary item" << item->index << (QObject *)(item->item);
|
||||
if (auto *att = static_cast<QQuickListViewAttached*>(item->attached)) {
|
||||
releaseSectionItem(att->m_sectionItem);
|
||||
att->m_sectionItem = nullptr;
|
||||
}
|
||||
releaseItem(item, reusableFlag);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
import QtQuick
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
|
||||
ListModel {
|
||||
id: listModel
|
||||
Component.onCompleted: reloadModel()
|
||||
}
|
||||
|
||||
property list<Item> sectionItems
|
||||
property int sectionType: 0
|
||||
property int sectionCount: 0
|
||||
|
||||
function reloadModel() {
|
||||
++listView.sectionType
|
||||
listModel.clear()
|
||||
for (let i = 0; i < 50; ++i) {
|
||||
listModel.append({sectionStr: listView.sectionType + ":" + listView.sectionCount++})
|
||||
}
|
||||
listView.sectionCount = 0
|
||||
}
|
||||
|
||||
width: 640
|
||||
height: 480
|
||||
spacing: 24
|
||||
boundsBehavior: Flickable.DragOverBounds
|
||||
displayMarginBeginning: 100
|
||||
displayMarginEnd: 100
|
||||
contentWidth: listView.width
|
||||
|
||||
model: listModel
|
||||
|
||||
section.property: "sectionStr"
|
||||
section.criteria: ViewSection.FullString
|
||||
section.labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart
|
||||
section.delegate: Item {
|
||||
id: item
|
||||
property string sectionData: section
|
||||
width: listView.width
|
||||
height: 30
|
||||
Rectangle {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: textDate.width + 20
|
||||
height: 16
|
||||
radius: 8
|
||||
color: "#E0E1D8"
|
||||
Text {
|
||||
id: textDate
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: 10
|
||||
text: item.sectionData
|
||||
}
|
||||
}
|
||||
Component.onCompleted: listView.sectionItems.push(item)
|
||||
Component.onDestruction: {
|
||||
let newSectionItems = []
|
||||
for (let index = 0; index < listView.sectionItems.length; index++) {
|
||||
if (listView.sectionItems[index] !== null && listView.sectionItems[index] != item)
|
||||
newSectionItems.push(listView.sectionItems[index])
|
||||
}
|
||||
listView.sectionItems = newSectionItems
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Item { width: listView.width; height: 10 + index }
|
||||
}
|
|
@ -122,6 +122,7 @@ private slots:
|
|||
void sectionPropertyChange();
|
||||
void sectionDelegateChange();
|
||||
void sectionsItemInsertion();
|
||||
void removeSectionsOnNonvisibleItems();
|
||||
void cacheBuffer();
|
||||
void positionViewAtBeginningEnd();
|
||||
void positionViewAtIndex();
|
||||
|
@ -2783,6 +2784,52 @@ void tst_QQuickListView::sectionsSnap()
|
|||
QCOMPARE(listview->contentY(), qreal(-50));
|
||||
}
|
||||
|
||||
void tst_QQuickListView::removeSectionsOnNonvisibleItems()
|
||||
{
|
||||
QScopedPointer<QQuickView> window(createView());
|
||||
window->setSource(testFileUrl("removeSectionsOnNonVisibleItems.qml"));
|
||||
window->show();
|
||||
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
|
||||
|
||||
auto verifySectionData = [](QObject *object, int sectionId) {
|
||||
auto sectionList = object->property("sectionItems").value<QQmlListProperty<QQuickItem>>();
|
||||
const int length = sectionList.count(§ionList);
|
||||
for (int index = 0; index < length; index++) {
|
||||
QQuickItem *currentItem = sectionList.at(§ionList, index);
|
||||
QString sectionData = currentItem->property("sectionData").value<QString>();
|
||||
QStringList sectionDataList = sectionData.split(":");
|
||||
QVERIFY(sectionDataList.at(0).toInt() == sectionId);
|
||||
}
|
||||
};
|
||||
|
||||
auto *listView = qobject_cast<QQuickListView*>(window->rootObject());
|
||||
QTRY_VERIFY(listView != nullptr);
|
||||
QVERIFY(listView->contentItem());
|
||||
|
||||
auto device = QPointingDevice::primaryPointingDevice();
|
||||
const int stopFlickCount = 15;
|
||||
int flickIndex = 0;
|
||||
// The issue is more apparent when the list view used in this test case
|
||||
// been flicked to the contentY: 965.
|
||||
const float contentYThreadhold = 965.;
|
||||
do {
|
||||
QQuickTest::pointerFlick(device, window.data(), 0, QPoint(100, 100), QPoint(100, 50), 125);
|
||||
QTRY_VERIFY(listView->isMovingVertically());
|
||||
QVERIFY(listView->contentY() != qreal(0));
|
||||
if (listView->contentY() >= contentYThreadhold) {
|
||||
listView->cancelFlick();
|
||||
break;
|
||||
}
|
||||
} while (++flickIndex <= stopFlickCount);
|
||||
|
||||
int verifySectionId = 0;
|
||||
verifySectionData(listView, ++verifySectionId);
|
||||
// Refresh the section item with the new model data
|
||||
QMetaObject::invokeMethod(listView, "reloadModel");
|
||||
QVERIFY(QQuickTest::qWaitForPolish(listView));
|
||||
verifySectionData(listView, ++verifySectionId);
|
||||
}
|
||||
|
||||
void tst_QQuickListView::currentIndex_delayedItemCreation()
|
||||
{
|
||||
QFETCH(bool, setCurrentToZero);
|
||||
|
|
Loading…
Reference in New Issue