730 qreal itemEnd = visiblePos;
731 if (visibleItems.size()) {
732 visiblePos = (*visibleItems.constBegin())->position();
733 itemEnd = (*(visibleItems.constEnd() - 1))->endPosition() + spacing;
736 int modelIndex = findLastVisibleIndex();
737 bool haveValidItems = modelIndex >= 0;
738 modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
740 if (haveValidItems && (bufferFrom > itemEnd+averageSize+spacing
741 || bufferTo < visiblePos - averageSize - spacing)) {
744 int count = (fillFrom - itemEnd) / (averageSize + spacing);
745 int newModelIdx = qBound(0, modelIndex + count, model->count());
746 count = newModelIdx - modelIndex;
748 releaseVisibleItems(reusableFlag);
749 modelIndex = newModelIdx;
750 visibleIndex = modelIndex;
751 visiblePos = itemEnd + count * (averageSize + spacing);
752 itemEnd = visiblePos;
756 QQmlIncubator::IncubationMode incubationMode = doBuffer ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested;
758 bool changed =
false;
761 while (modelIndex < model->count() && pos <= fillTo) {
762 if (!(item =
static_cast<
FxListItemSG*>(createItem(modelIndex, incubationMode))))
764 qCDebug(lcItemViewDelegateLifecycle) <<
"refill: append item" << modelIndex <<
"pos" << pos <<
"buffer" << doBuffer <<
"item" << (QObject *)(item->item);
765#if QT_CONFIG(quick_viewtransitions)
766 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition,
true))
768 item->setPosition(pos,
true);
770 QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
771 pos += item->size() + spacing;
772 visibleItems.append(item);
777 if (doBuffer && requestedIndex != -1)
780 while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > fillFrom) {
781 if (!(item =
static_cast<FxListItemSG*>(createItem(visibleIndex-1, incubationMode))))
783 qCDebug(lcItemViewDelegateLifecycle) <<
"refill: prepend item" << visibleIndex-1 <<
"current top pos" << visiblePos <<
"buffer" << doBuffer <<
"item" << (QObject *)(item->item);
785 visiblePos -= item->size() + spacing;
786#if QT_CONFIG(quick_viewtransitions)
787 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition,
true))
789 item->setPosition(visiblePos,
true);
791 QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
792 visibleItems.prepend(item);
879 if (!visibleItems.isEmpty()) {
880 const qreal from = isContentFlowReversed() ? -position()-displayMarginBeginning-size() : position()-displayMarginBeginning;
881 const qreal to = isContentFlowReversed() ? -position()+displayMarginEnd : position()+size()+displayMarginEnd;
883 FxListItemSG *firstItem =
static_cast<FxListItemSG *>(visibleItems.constFirst());
884 bool fixedCurrent = currentItem && firstItem->item == currentItem->item;
886#if QT_CONFIG(quick_viewtransitions)
888
889 if (transitioner && transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition,
true))
890 resetFirstItemPosition(isContentFlowReversed() ? -firstItem->position()-firstItem->size() : firstItem->position());
893 firstVisibleItemPosition = firstItem->position();
894 qreal sum = firstItem->size();
895 qreal pos = firstItem->position() + firstItem->size() + spacing;
896 firstItem->setVisible(firstItem->endPosition() >= from && firstItem->position() <= to);
901 firstItem->setPosition(firstItem->position());
903 for (
int i=1; i < visibleItems.size(); ++i) {
904 FxListItemSG *item =
static_cast<FxListItemSG*>(visibleItems.at(i));
905 if (item->index >= fromModelIndex) {
906 item->setPosition(pos);
907 item->setVisible(item->endPosition() >= from && item->position() <= to);
909 pos += item->size() + spacing;
911 fixedCurrent = fixedCurrent || (currentItem && item->item == currentItem->item);
913 averageSize = qRound(sum / visibleItems.size());
916 if (currentIndex >= 0 && currentItem && !fixedCurrent)
917 static_cast<FxListItemSG*>(currentItem)->setPosition(positionAt(currentIndex));
972 bool changed =
false;
974 if (trackedItem == highlight.get())
975 trackedItem =
nullptr;
978 highlightPosAnimator.reset();
979 highlightWidthAnimator.reset();
980 highlightHeightAnimator.reset();
981 highlightPosAnimator =
nullptr;
982 highlightWidthAnimator =
nullptr;
983 highlightHeightAnimator =
nullptr;
993 QQuickItem *item = createHighlightItem();
995 std::unique_ptr<FxListItemSG> newHighlight
996 = std::make_unique<FxListItemSG>(item, q,
true);
997 newHighlight->trackGeometry(
true);
1000 newHighlight->setSize(
static_cast<FxListItemSG*>(currentItem)->itemSize());
1001 newHighlight->setPosition(
static_cast<FxListItemSG*>(currentItem)->itemPosition());
1003 const QLatin1String posProp(orient == QQuickListView::Vertical ?
"y" :
"x");
1004 highlightPosAnimator = std::make_unique<QSmoothedAnimation>();
1005 highlightPosAnimator->target = QQmlProperty(item, posProp);
1006 highlightPosAnimator->velocity = highlightMoveVelocity;
1007 highlightPosAnimator->userDuration = highlightMoveDuration;
1009 highlightWidthAnimator = std::make_unique<QSmoothedAnimation>();
1010 highlightWidthAnimator->velocity = highlightResizeVelocity;
1011 highlightWidthAnimator->userDuration = highlightResizeDuration;
1012 highlightWidthAnimator->target = QQmlProperty(item, QStringLiteral(
"width"));
1014 highlightHeightAnimator = std::make_unique<QSmoothedAnimation>();
1015 highlightHeightAnimator->velocity = highlightResizeVelocity;
1016 highlightHeightAnimator->userDuration = highlightResizeDuration;
1017 highlightHeightAnimator->target = QQmlProperty(item, QStringLiteral(
"height"));
1019 highlight = std::move(newHighlight);
1024 emit q->highlightItemChanged();
1078 Q_Q(QQuickListView);
1079 QQuickItem *sectionItem =
nullptr;
1086 sectionItem->setVisible(
true);
1087 QQmlContext *context = QQmlEngine::contextForObject(sectionItem)->parentContext();
1088 setSectionHelper(context, sectionItem, section);
1090 QQmlComponent* delegate = sectionCriteria->delegate();
1091 const bool reuseExistingContext = delegate->isBound();
1092 auto delegatePriv = QQmlComponentPrivate::get(delegate);
1093 QQmlPropertyCache::ConstPtr rootPropertyCache;
1095 QQmlContext *creationContext = sectionCriteria->delegate()->creationContext();
1096 auto baseContext = creationContext ? creationContext : qmlContext(q);
1098 QQmlContext *context = reuseExistingContext ? baseContext :
new QQmlContext(baseContext);
1099 QObject *nobj = delegate->beginCreate(context);
1101 if (delegatePriv->hadTopLevelRequiredProperties()) {
1102 delegate->setInitialProperties(nobj, {{QLatin1String(
"section"), section}});
1103 }
else if (!reuseExistingContext) {
1104 context->setContextProperty(QLatin1String(
"section"), section);
1106 if (!reuseExistingContext)
1107 QQml_setParent_noEvent(context, nobj);
1108 sectionItem = qobject_cast<QQuickItem *>(nobj);
1112 if (qFuzzyIsNull(sectionItem->z()))
1113 sectionItem->setZ(2);
1114 QQml_setParent_noEvent(sectionItem, contentItem);
1115 sectionItem->setParentItem(contentItem);
1118 auto *attached =
static_cast<QQuickListViewAttached*>(qmlAttachedPropertiesObject<QQuickListView>(sectionItem));
1119 attached->setView(q);
1120 }
else if (!reuseExistingContext) {
1123 sectionCriteria->delegate()->completeCreate();
1127 QQuickItemPrivate::get(sectionItem)->addItemChangeListener(
this, QQuickItemPrivate::Geometry);
1194 if (!sectionCriteria || !sectionCriteria->delegate()
1195 || (!sectionCriteria->labelPositioning() && !currentSectionItem && !nextSectionItem))
1199 qreal viewPos = isFlowReversed ? -position()-size() : position();
1200 qreal startPos = hasStickyHeader() ? header->endPosition() : viewPos;
1201 qreal endPos = hasStickyFooter() ? footer->position() : viewPos + size();
1203 QQuickItem *sectionItem =
nullptr;
1204 QQuickItem *lastSectionItem =
nullptr;
1206 while (index < visibleItems.size()) {
1207 if (QQuickItem *section =
static_cast<FxListItemSG *>(visibleItems.at(index))->section()) {
1210 qreal sectionPos = orient == QQuickListView::Vertical ? section->y() : section->x();
1211 qreal sectionSize = orient == QQuickListView::Vertical ? section->height() : section->width();
1213 if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
1214 visTop = isFlowReversed ? -sectionPos-sectionSize >= startPos : sectionPos >= startPos;
1216 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd)
1217 visBot = isFlowReversed ? -sectionPos <= endPos : sectionPos + sectionSize < endPos;
1218 section->setVisible(visBot && visTop);
1219 if (visTop && !sectionItem)
1220 sectionItem = section;
1221 if (isFlowReversed) {
1222 if (-sectionPos <= endPos)
1223 lastSectionItem = section;
1225 if (sectionPos + sectionSize < endPos)
1226 lastSectionItem = section;
1233 if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart && isValid() && visibleItems.size()) {
1235 currentSectionItem = getSectionItem(currentSection);
1236 }
else if (QString::compare(currentStickySection, currentSection, Qt::CaseInsensitive)) {
1237 QQmlContext *context = QQmlEngine::contextForObject(currentSectionItem)->parentContext();
1238 setSectionHelper(context, currentSectionItem, currentSection);
1240 currentStickySection = currentSection;
1244 qreal sectionSize = orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
1245 bool atBeginning = orient == QQuickListView::Vertical ? (isBottomToTop() ? vData.atEnd : vData.atBeginning) : (isRightToLeft() ? hData.atEnd : hData.atBeginning);
1247 currentSectionItem->setVisible(!atBeginning && (!header || hasStickyHeader() || header->endPosition() < viewPos));
1248 qreal pos = isFlowReversed ? position() + size() - sectionSize : startPos;
1250 pos = isFlowReversed ? qMin(-header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
1252 qreal sectionPos = orient == QQuickListView::Vertical ? sectionItem->y() : sectionItem->x();
1253 pos = isFlowReversed ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize);
1256 pos = isFlowReversed ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
1257 if (orient == QQuickListView::Vertical)
1258 currentSectionItem->setY(pos);
1260 currentSectionItem->setX(pos);
1267 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd && isValid() && visibleItems.size()) {
1269 nextSectionItem = getSectionItem(nextSection);
1270 }
else if (QString::compare(nextStickySection, nextSection, Qt::CaseInsensitive)) {
1271 QQmlContext *context = QQmlEngine::contextForObject(nextSectionItem)->parentContext();
1272 setSectionHelper(context, nextSectionItem, nextSection);
1274 nextStickySection = nextSection;
1278 qreal sectionSize = orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1279 nextSectionItem->setVisible(!nextSection.isEmpty());
1280 qreal pos = isFlowReversed ? position() : endPos - sectionSize;
1282 pos = isFlowReversed ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
1283 if (lastSectionItem) {
1284 qreal sectionPos = orient == QQuickListView::Vertical ? lastSectionItem->y() : lastSectionItem->x();
1285 pos = isFlowReversed ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize);
1288 pos = isFlowReversed ? qMin(-header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
1289 if (orient == QQuickListView::Vertical)
1290 nextSectionItem->setY(pos);
1292 nextSectionItem->setX(pos);
1342 Q_Q(QQuickListView);
1343 if (!sectionCriteria || visibleItems.isEmpty()) {
1344 if (!currentSection.isEmpty()) {
1345 currentSection.clear();
1346 emit q->currentSectionChanged();
1350 bool inlineSections = sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels;
1351 qreal viewPos = isContentFlowReversed() ? -position()-size() : position();
1352 qreal startPos = hasStickyHeader() ? header->endPosition() : viewPos;
1354 int modelIndex = visibleIndex;
1355 while (index < visibleItems.size()) {
1356 FxViewItem *item = visibleItems.at(index);
1357 if (item->endPosition() > startPos)
1359 if (item->index != -1)
1360 modelIndex = item->index;
1364 QString newSection = currentSection;
1365 if (index < visibleItems.size())
1366 newSection = visibleItems.at(index)->attached->section();
1368 newSection = (*visibleItems.constBegin())->attached->section();
1369 if (newSection != currentSection) {
1370 currentSection = newSection;
1372 emit q->currentSectionChanged();
1375 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd) {
1380 QString lastSection = currentSection;
1381 qreal endPos = hasStickyFooter() ? footer->position() : viewPos + size();
1382 if (nextSectionItem && !inlineSections)
1383 endPos -= orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1384 while (index < visibleItems.size()) {
1385 FxListItemSG *listItem =
static_cast<FxListItemSG *>(visibleItems.at(index));
1386 if (listItem->itemPosition() >= endPos)
1388 if (listItem->index != -1)
1389 modelIndex = listItem->index;
1390 lastSection = listItem->attached->section();
1394 if (lastVisibleSection != lastSection) {
1395 nextSection = QString();
1396 lastVisibleSection = lastSection;
1397 for (
int i = modelIndex; i < itemCount; ++i) {
1398 QString section = sectionAt(i);
1399 if (section != lastSection) {
1400 nextSection = section;
1532 Q_Q(QQuickListView);
1533 bool created =
false;
1535 QQuickItem *item = createComponentItem(headerComponent, 1.0);
1538 header =
new FxListItemSG(item, q,
true);
1539 header->trackGeometry(
true);
1543 FxListItemSG *listItem =
static_cast<FxListItemSG*>(header);
1544 if (headerPositioning == QQuickListView::OverlayHeader) {
1546 }
else if (visibleItems.size()) {
1547 const bool fixingUp = (orient == QQuickListView::Vertical ? vData : hData).fixingUp;
1548 if (headerPositioning == QQuickListView::PullBackHeader) {
1549 qreal headerPosition = listItem->position();
1552 if (fixingUp && !headerNeedsSeparateFixup)
1553 headerPosition = viewPos - headerSize();
1556 qreal clampedPos = qMax(originPosition() - headerSize(), qMin(headerPosition, lastPosition() - size()));
1557 listItem->setPosition(qBound(viewPos - headerSize(), clampedPos, viewPos),
false,
false);
1559 qreal startPos = originPosition();
1560 if (visibleIndex == 0) {
1561 listItem->setPosition(startPos - headerSize(),
false,
false);
1563 if (position() <= startPos || listItem->position() > startPos - headerSize())
1564 listItem->setPosition(startPos - headerSize(),
false,
false);
1568 listItem->setPosition(-headerSize(),
false,
false);
1572 emit q->headerItemChanged();
1594 const QRectF &oldGeometry)
1596 Q_Q(QQuickListView);
1598 QQuickItemViewPrivate::itemGeometryChanged(item, change, oldGeometry);
1599 if (!q->isComponentComplete())
1602 if (currentItem && currentItem->item == item) {
1604 const qreal pos = position();
1605 const qreal sz = size();
1606 const qreal from = contentFlowReversed ? -pos - displayMarginBeginning - sz : pos - displayMarginBeginning;
1607 const qreal to = contentFlowReversed ? -pos + displayMarginEnd : pos + sz + displayMarginEnd;
1608 QQuickItemPrivate::get(currentItem->item)->setCulled(currentItem->endPosition() < from || currentItem->position() > to);
1611 if (item != contentItem && (!highlight || item != highlight->item)) {
1612 if ((orient == QQuickListView::Vertical && change.heightChange())
1613 || (orient == QQuickListView::Horizontal && change.widthChange())) {
1617 if (visibleItems.size() && item == visibleItems.constFirst()->item) {
1618 FxListItemSG *listItem =
static_cast<FxListItemSG*>(visibleItems.constFirst());
1619#if QT_CONFIG(quick_viewtransitions)
1620 if (listItem->transitionScheduledOrRunning())
1623 if (orient == QQuickListView::Vertical) {
1624 const qreal oldItemEndPosition = verticalLayoutDirection == QQuickItemView::BottomToTop ? -oldGeometry.y() : oldGeometry.y() + oldGeometry.height();
1625 const qreal heightDiff = item->height() - oldGeometry.height();
1626 if (verticalLayoutDirection == QQuickListView::TopToBottom && oldItemEndPosition < q->contentY())
1627 listItem->setPosition(listItem->position() - heightDiff,
true);
1628 else if (verticalLayoutDirection == QQuickListView::BottomToTop && oldItemEndPosition > q->contentY())
1629 listItem->setPosition(listItem->position() + heightDiff,
true);
1631 const qreal oldItemEndPosition = q->effectiveLayoutDirection() == Qt::RightToLeft ? -oldGeometry.x() : oldGeometry.x() + oldGeometry.width();
1632 const qreal widthDiff = item->width() - oldGeometry.width();
1633 if (q->effectiveLayoutDirection() == Qt::LeftToRight && oldItemEndPosition < q->contentX())
1634 listItem->setPosition(listItem->position() - widthDiff,
true);
1635 else if (q->effectiveLayoutDirection() == Qt::RightToLeft && oldItemEndPosition > q->contentX())
1636 listItem->setPosition(listItem->position() + widthDiff,
true);
1639 forceLayoutPolish();
1654 if (orient == QQuickListView::Horizontal && &data == &vData) {
1655 if (flickableDirection != QQuickFlickable::HorizontalFlick)
1656 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1658 }
else if (orient == QQuickListView::Vertical && &data == &hData) {
1659 if (flickableDirection != QQuickFlickable::VerticalFlick)
1660 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1665 if (visibleItems.size() == 0)
1669 fixupMode = moveReason == Mouse ? fixupMode : Immediate;
1670 bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
1672 qreal viewPos = isContentFlowReversed() ? -position()-size() : position();
1674 if (snapMode != QQuickListView::NoSnap && moveReason != QQuickListViewPrivate::SetIndex) {
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691 qreal tempPosition = isContentFlowReversed() ? -position()-size() : position();
1692 if (snapMode == QQuickListView::SnapOneItem && moveReason == Mouse) {
1694 qreal dist = data.move.value() - data.pressPos;
1697 bias = averageSize/2;
1699 bias = -averageSize/2;
1700 if (isContentFlowReversed())
1702 tempPosition -= bias;
1705 qreal snapOffset = 0;
1706 qreal overlayHeaderOffset = 0;
1707 bool isHeaderWithinBounds =
false;
1709 qreal visiblePartOfHeader = header->position() + header->size() - tempPosition;
1710 isHeaderWithinBounds = visiblePartOfHeader > 0;
1711 switch (headerPositioning) {
1712 case QQuickListView::OverlayHeader:
1713 snapOffset = header->size();
1714 overlayHeaderOffset = header->size();
1716 case QQuickListView::InlineHeader:
1717 if (isHeaderWithinBounds && tempPosition < originPosition())
1721 snapOffset = header->size() / 2;
1723 case QQuickListView::PullBackHeader:
1724 desiredHeaderVisible = visiblePartOfHeader > header->size()/2;
1725 if (qFuzzyCompare(header->position(), tempPosition)) {
1727 snapOffset = header->size();
1731 snapOffset = header->size();
1732 overlayHeaderOffset = header->size();
1741 if (strictHighlightRange)
1744 FxViewItem *topItem = snapItemAt(tempPosition + snapOffset + highlightRangeStart);
1745 FxViewItem *bottomItem = snapItemAt(tempPosition + snapOffset + highlightRangeEnd);
1746 if (strictHighlightRange && currentItem) {
1748 if (!topItem || (topItem->index != currentIndex && fixupMode == Immediate))
1749 topItem = currentItem;
1750 if (!bottomItem || (bottomItem->index != currentIndex && fixupMode == Immediate))
1751 bottomItem = currentItem;
1755 bool isInBounds = -position() > maxExtent && -position() <= minExtent;
1757 if (header && !topItem && isInBounds) {
1759 switch (headerPositioning) {
1760 case QQuickListView::OverlayHeader:
1761 pos = startPosition() - overlayHeaderOffset;
1763 case QQuickListView::InlineHeader:
1764 pos = isContentFlowReversed() ? header->size() - size() : header->position();
1766 case QQuickListView::PullBackHeader:
1767 pos = isContentFlowReversed() ? -size() : startPosition();
1770 }
else if (topItem && (isInBounds || strictHighlightRange)) {
1771 if (topItem->index == 0 && header && !hasStickyHeader() && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) {
1772 pos = isContentFlowReversed() ? -header->position() + highlightRangeStart - size() : (header->position() - highlightRangeStart + header->size());
1774 if (header && headerPositioning == QQuickListView::PullBackHeader) {
1777 if (qFuzzyCompare(tempPosition, header->position())) {
1779 if (isContentFlowReversed())
1780 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + snapOffset;
1782 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - snapOffset;
1789 if (isContentFlowReversed())
1790 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + headerSize();
1792 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - headerSize();
1796 if (isContentFlowReversed())
1797 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size();
1799 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart;
1810 pos = qBound(-minExtent, pos, -maxExtent);
1811 desiredViewportPosition = isContentFlowReversed() ? -pos - size() : pos;
1813 FxListItemSG *headerItem =
static_cast<FxListItemSG*>(header);
1814 fixupHeaderPosition = headerItem->position();
1817 QObjectPrivate::connect(&timeline, &QQuickTimeLine::updated,
this, &QQuickListViewPrivate::fixupHeader);
1818 QObjectPrivate::connect(&timeline, &QQuickTimeLine::completed,
this, &QQuickListViewPrivate::fixupHeaderCompleted);
1821 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + overlayHeaderOffset;
1823 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - overlayHeaderOffset;
1826 }
else if (bottomItem && isInBounds) {
1827 if (isContentFlowReversed())
1828 pos = -
static_cast<FxListItemSG*>(bottomItem)->itemPosition() + highlightRangeEnd - size() + overlayHeaderOffset;
1830 pos =
static_cast<FxListItemSG*>(bottomItem)->itemPosition() - highlightRangeEnd - overlayHeaderOffset;
1832 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1838 && (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
1839 && currentSectionItem) {
1840 auto sectionSize = (orient == QQuickListView::Vertical) ? currentSectionItem->height()
1841 : currentSectionItem->width();
1842 if (isContentFlowReversed())
1848 pos = qBound(-minExtent, pos, -maxExtent);
1850 qreal dist = qAbs(data.move + pos);
1855 timeline.reset(data.move);
1856 if (fixupMode != Immediate) {
1857 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1858 data.fixingUp =
true;
1860 timeline.set(data.move, -pos);
1862 vTime = timeline.time();
1864 }
else if (currentItem && strictHighlightRange && moveReason != QQuickListViewPrivate::SetIndex) {
1866 qreal pos =
static_cast<FxListItemSG*>(currentItem)->itemPosition();
1867 if (viewPos < pos +
static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd)
1868 viewPos = pos +
static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd;
1869 if (viewPos > pos - highlightRangeStart)
1870 viewPos = pos - highlightRangeStart;
1871 if (isContentFlowReversed())
1872 viewPos = -viewPos-size();
1874 timeline.reset(data.move);
1875 if (viewPos != position()) {
1876 if (fixupMode != Immediate) {
1877 if (fixupMode == ExtentChanged && data.fixingUp)
1878 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::OutQuad), fixupDuration/2);
1880 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1881 data.fixingUp =
true;
1883 timeline.set(data.move, -viewPos);
1886 vTime = timeline.time();
1888 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1890 data.inOvershoot =
false;
1895 QQuickTimeLineCallback::Callback fixupCallback, QEvent::Type eventType, qreal velocity)
1897 data.fixingUp =
false;
1899 if ((!haveHighlightRange || highlightRange != QQuickListView::StrictlyEnforceRange) && snapMode == QQuickListView::NoSnap) {
1901 return QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, eventType, velocity);
1903 qreal maxDistance = 0;
1904 const qreal dataValue =
1909 if (data.move.value() < minExtent) {
1910 if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1912 qreal bias = averageSize / 2 + 1 - (pressed ? data.pressPos : 0);
1913 if (isContentFlowReversed())
1915 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) - bias) + highlightRangeStart;
1916 maxDistance = qAbs(data.flickTarget - data.move.value());
1917 velocity = maxVelocity;
1919 maxDistance = qAbs(minExtent - data.move.value());
1922 if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
1923 data.flickTarget = minExtent;
1925 if (data.move.value() > maxExtent) {
1926 if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1928 qreal bias = averageSize / 2 + 1 - (pressed ? data.pressPos : 0);
1929 if (isContentFlowReversed())
1932 -snapPosAt(-(dataValue - highlightRangeStart) + bias) + highlightRangeStart;
1933 maxDistance = qAbs(data.flickTarget - data.move.value());
1934 velocity = -maxVelocity;
1936 maxDistance = qAbs(maxExtent - data.move.value());
1939 if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
1940 data.flickTarget = maxExtent;
1942 bool overShoot = boundsBehavior & QQuickFlickable::OvershootBounds;
1943 if (maxDistance > 0 || overShoot) {
1949 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
1955 if (!hData.flicking && !vData.flicking) {
1957 qreal accel = eventType == QEvent::Wheel ? wheelDeceleration : deceleration;
1959 overshootDist = 0.0;
1961 qreal dist = v2 / (accel * 2.0) + averageSize/4;
1962 if (maxDistance > 0)
1963 dist = qMin(dist, maxDistance);
1966 if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickListView::SnapOneItem) {
1967 if (snapMode != QQuickListView::SnapOneItem) {
1968 qreal distTemp = isContentFlowReversed() ? -dist : dist;
1969 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + distTemp) + highlightRangeStart;
1973 if (data.flickTarget > minExtent) {
1974 overshootDist = overShootDistance(vSize);
1975 data.flickTarget += overshootDist;
1976 }
else if (data.flickTarget < maxExtent) {
1977 overshootDist = overShootDistance(vSize);
1978 data.flickTarget -= overshootDist;
1981 qreal adjDist = -data.flickTarget + data.move.value();
1982 if (qAbs(adjDist) > qAbs(dist)) {
1984 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
1993 accel = v2 / (2.0f * qAbs(dist));
1994 }
else if (overShoot) {
1995 data.flickTarget = data.move.value() - dist;
1996 if (data.flickTarget > minExtent) {
1997 overshootDist = overShootDistance(vSize);
1998 data.flickTarget += overshootDist;
1999 }
else if (data.flickTarget < maxExtent) {
2000 overshootDist = overShootDistance(vSize);
2001 data.flickTarget -= overshootDist;
2004 timeline.reset(data.move);
2005 timeline.accel(data.move, v, accel, maxDistance + overshootDist);
2006 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback,
this));
2011 qreal newtarget = data.flickTarget;
2012 if (snapMode != QQuickListView::NoSnap || highlightRange == QQuickListView::StrictlyEnforceRange) {
2013 qreal tempFlickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget;
2014 newtarget = -snapPosAt(-(tempFlickTarget - highlightRangeStart)) + highlightRangeStart;
2015 newtarget = isContentFlowReversed() ? -newtarget+size() : newtarget;
2017 if (velocity < 0 && newtarget <= maxExtent)
2018 newtarget = maxExtent - overshootDist;
2019 else if (velocity > 0 && newtarget >= minExtent)
2020 newtarget = minExtent + overshootDist;
2021 if (newtarget == data.flickTarget) {
2022 if (qAbs(velocity) < _q_MinimumFlickVelocity)
2026 data.flickTarget = newtarget;
2027 qreal dist = -newtarget + data.move.value();
2028 if ((v < 0 && dist < 0) || (v > 0 && dist > 0)) {
2030 timeline.reset(data.move);
2031 fixup(data, minExtent, maxExtent);
2034 timeline.reset(data.move);
2035 timeline.accelDistance(data.move, v, -dist);
2036 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback,
this));
2041 timeline.reset(data.move);
2042 fixup(data, minExtent, maxExtent);
3491void QQuickListView::viewportMoved(Qt::Orientations orient)
3493 Q_D(QQuickListView);
3494 QQuickItemView::viewportMoved(orient);
3496 if (!d->itemCount) {
3497 if (d->hasStickyHeader())
3499 if (d->hasStickyFooter())
3505 if (d->inViewportMoved)
3507 d->inViewportMoved =
true;
3510 if (d->isBottomToTop())
3511 d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
3513 d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
3515 if (d->isRightToLeft())
3516 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
3518 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
3521 d->refillOrLayout();
3524 qreal from = d->isContentFlowReversed() ? -d->position()-d->displayMarginBeginning-d->size() : d->position()-d->displayMarginBeginning;
3525 qreal to = d->isContentFlowReversed() ? -d->position()+d->displayMarginEnd : d->position()+d->size()+d->displayMarginEnd;
3526 for (FxViewItem *item : std::as_const(d->visibleItems)) {
3528 QQuickItemPrivate::get(item->item)->setCulled(item->endPosition() < from || item->position() > to);
3531 QQuickItemPrivate::get(d->currentItem->item)->setCulled(d->currentItem->endPosition() < from || d->currentItem->position() > to);
3533 if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
3534 d->moveReason = QQuickListViewPrivate::Mouse;
3535 if (d->moveReason != QQuickListViewPrivate::SetIndex) {
3536 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
3538 qreal pos = d->highlight->position();
3539 qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
3540 if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
3541 pos = viewPos + d->highlightRangeEnd - d->highlight->size();
3542 if (pos < viewPos + d->highlightRangeStart)
3543 pos = viewPos + d->highlightRangeStart;
3544 if (pos != d->highlight->position()) {
3545 d->highlightPosAnimator->stop();
3546 static_cast<FxListItemSG*>(d->highlight.get())->setPosition(pos);
3548 d->updateHighlight();
3552 if (FxViewItem *snapItem = d->snapItemAt(d->highlight->position())) {
3553 if (snapItem->index >= 0 && snapItem->index != d->currentIndex)
3554 d->updateCurrent(snapItem->index);
3559 if ((d->hData.flicking || d->vData.flicking) && d->correctFlick && !d->inFlickCorrection) {
3560 d->inFlickCorrection =
true;
3563 if (yflick() && !d->vData.inOvershoot) {
3564 if (d->vData.velocity > 0) {
3565 const qreal minY = minYExtent();
3566 if ((minY - d->vData.move.value() < height()/2 || d->vData.flickTarget - d->vData.move.value() < height()/2)
3567 && minY != d->vData.flickTarget)
3568 d->flickY(QEvent::TouchUpdate, -d->vData.smoothVelocity.value());
3569 }
else if (d->vData.velocity < 0) {
3570 const qreal maxY = maxYExtent();
3571 if ((d->vData.move.value() - maxY < height()/2 || d->vData.move.value() - d->vData.flickTarget < height()/2)
3572 && maxY != d->vData.flickTarget)
3573 d->flickY(QEvent::TouchUpdate, -d->vData.smoothVelocity.value());
3577 if (xflick() && !d->hData.inOvershoot) {
3578 if (d->hData.velocity > 0) {
3579 const qreal minX = minXExtent();
3580 if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2)
3581 && minX != d->hData.flickTarget)
3582 d->flickX(QEvent::TouchUpdate, -d->hData.smoothVelocity.value());
3583 }
else if (d->hData.velocity < 0) {
3584 const qreal maxX = maxXExtent();
3585 if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2)
3586 && maxX != d->hData.flickTarget)
3587 d->flickX(QEvent::TouchUpdate, -d->hData.smoothVelocity.value());
3590 d->inFlickCorrection =
false;
3592 if (d->hasStickyHeader())
3594 if (d->hasStickyFooter())
3596 if (d->sectionCriteria) {
3597 d->updateCurrentSection();
3598 d->updateStickySections();
3600 d->inViewportMoved =
false;
3747 Q_Q(QQuickListView);
3748#if QT_CONFIG(quick_viewtransitions)
3749 Q_UNUSED(movingIntoView)
3751 int modelIndex = change.index;
3752 int count = change.count;
3754 if (q->size().isNull() && visibleItems.isEmpty())
3757 qreal tempPos = isContentFlowReversed() ? -position()-size() : position();
3758 int index = visibleItems.size() ? mapFromModel(modelIndex) : 0;
3759 qreal lastVisiblePos = buffer + displayMarginEnd + tempPos + size();
3762 int i = visibleItems.size() - 1;
3763 while (i > 0 && visibleItems.at(i)->index == -1)
3765 if (i == 0 && visibleItems.constFirst()->index == -1) {
3767 index = visibleItems.size();
3768 }
else if (visibleItems.at(i)->index + 1 == modelIndex
3769 && visibleItems.at(i)->endPosition() <= lastVisiblePos) {
3771 index = visibleItems.size();
3773 if (modelIndex < visibleIndex) {
3775 visibleIndex += count;
3776 for (FxViewItem *item : std::as_const(visibleItems)) {
3777 if (item->index != -1 && item->index >= modelIndex)
3778 item->index += count;
3787 if (visibleItems.size()) {
3788 pos = index < visibleItems.size() ? visibleItems.at(index)->position()
3789 : visibleItems.constLast()->endPosition() + spacing;
3793 for (FxViewItem *item : std::as_const(visibleItems)) {
3794 if (item->index != -1 && item->index >= modelIndex) {
3795 item->index += count;
3796#if QT_CONFIG(quick_viewtransitions)
3797 if (change.isMove())
3798 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition,
false);
3800 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition,
false);
3805 bool visibleAffected =
false;
3806 if (insertResult->visiblePos.isValid() && pos < insertResult->visiblePos) {
3808 int insertionIdx = index;
3809 qreal from = tempPos - displayMarginBeginning - buffer;
3811 if (insertionIdx < visibleIndex) {
3814 insertResult->sizeChangesBeforeVisiblePos += count * (averageSize + spacing);
3818 for (; it.hasNext() && pos >= from; it
.next()) {
3820 FxViewItem *item =
nullptr;
3821 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(it.index))))
3822 item->index = it.index;
3824 item = createItem(it.index, QQmlIncubator::Synchronous);
3830 visibleAffected =
true;
3831 visibleItems.insert(insertionIdx, item);
3832 if (insertionIdx == 0)
3833 insertResult->changedFirstItem =
true;
3834 if (!change.isMove()) {
3835 addedItems->append(item);
3836#if QT_CONFIG(quick_viewtransitions)
3838 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition,
true);
3841 static_cast<FxListItemSG *>(item)->setPosition(pos,
true);
3843 insertResult->sizeChangesBeforeVisiblePos += item->size() + spacing;
3844 pos -= item->size() + spacing;
3849 int firstOkIdx = -1;
3850 for (
int i = 0; i <= insertionIdx && i < visibleItems.size() - 1; i++) {
3851 if (visibleItems.at(i)->index + 1 != visibleItems.at(i + 1)->index) {
3856 for (
int i = 0; i < firstOkIdx; i++) {
3857 FxViewItem *nvItem = visibleItems.takeFirst();
3858 addedItems->removeOne(nvItem);
3864 for (; it.hasNext() && pos <= lastVisiblePos; it
.next()) {
3865 visibleAffected =
true;
3866 FxViewItem *item =
nullptr;
3867 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(it.index))))
3868 item->index = it.index;
3869#if QT_CONFIG(quick_viewtransitions)
3870 bool newItem = !item;
3874 item = createItem(it.index, QQmlIncubator::Synchronous);
3878 releaseItem(item, reusableFlag);
3882 if (index < visibleItems.size())
3883 visibleItems.insert(index, item);
3885 visibleItems.append(item);
3887 insertResult->changedFirstItem =
true;
3888 if (change.isMove()) {
3891#if QT_CONFIG(quick_viewtransitions)
3892 if (newItem && transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition,
true))
3893 movingIntoView->append(MovedItem(item, change.moveKey(item->index)));
3896 addedItems->append(item);
3897#if QT_CONFIG(quick_viewtransitions)
3899 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition,
true);
3902 static_cast<FxListItemSG *>(item)->setPosition(pos,
true);
3904 insertResult->sizeChangesAfterVisiblePos += item->size() + spacing;
3905 pos += item->size() + spacing;
3910 if (0 < index && index < visibleItems.size()) {
3911 FxViewItem *prevItem = visibleItems.at(index - 1);
3912 FxViewItem *item = visibleItems.at(index);
3913 if (prevItem->index != item->index - 1) {
3915#if QT_CONFIG(quick_viewtransitions)
3916 qreal prevPos = prevItem->position();
3918 while (i < visibleItems.size()) {
3919 FxListItemSG *nvItem =
static_cast<FxListItemSG *>(visibleItems.takeLast());
3920 insertResult->sizeChangesAfterVisiblePos -= nvItem->size() + spacing;
3921 addedItems->removeOne(nvItem);
3922#if QT_CONFIG(quick_viewtransitions)
3923 if (nvItem->transitionScheduledOrRunning())
3924 nvItem->setPosition(prevPos + (nvItem->index - prevItem->index) * averageSize);
3932 updateVisibleIndex();
3934 return visibleAffected;