743 qreal itemEnd = visiblePos;
744 if (visibleItems.size()) {
745 visiblePos = (*visibleItems.constBegin())->position();
746 itemEnd = (*(visibleItems.constEnd() - 1))->endPosition() + spacing;
749 int modelIndex = findLastVisibleIndex();
750 bool haveValidItems = modelIndex >= 0;
751 modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
753 if (haveValidItems && (bufferFrom > itemEnd+averageSize+spacing
754 || bufferTo < visiblePos - averageSize - spacing)) {
757 int count = (fillFrom - itemEnd) / (averageSize + spacing);
758 int newModelIdx = qBound(0, modelIndex + count, model->count());
759 count = newModelIdx - modelIndex;
761 releaseVisibleItems(reusableFlag);
762 modelIndex = newModelIdx;
763 visibleIndex = modelIndex;
764 visiblePos = itemEnd + count * (averageSize + spacing);
765 itemEnd = visiblePos;
769 QQmlIncubator::IncubationMode incubationMode = doBuffer ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested;
771 bool changed =
false;
774 while (modelIndex < model->count() && pos <= fillTo) {
775 if (!(item =
static_cast<
FxListItemSG*>(createItem(modelIndex, incubationMode))))
777 qCDebug(lcItemViewDelegateLifecycle) <<
"refill: append item" << modelIndex <<
"pos" << pos <<
"buffer" << doBuffer <<
"item" << (QObject *)(item->item);
778#if QT_CONFIG(quick_viewtransitions)
779 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition,
true))
781 item->setPosition(pos,
true);
783 QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
784 pos += item->size() + spacing;
785 visibleItems.append(item);
790 if (doBuffer && requestedIndex != -1)
793 while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > fillFrom) {
794 if (!(item =
static_cast<
FxListItemSG*>(createItem(visibleIndex-1, incubationMode))))
796 qCDebug(lcItemViewDelegateLifecycle) <<
"refill: prepend item" << visibleIndex-1 <<
"current top pos" << visiblePos <<
"buffer" << doBuffer <<
"item" << (QObject *)(item->item);
798 visiblePos -= item->size() + spacing;
799#if QT_CONFIG(quick_viewtransitions)
800 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition,
true))
802 item->setPosition(visiblePos,
true);
804 QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
805 visibleItems.prepend(item);
809 if (changed && sectionCriteria)
895 if (!visibleItems.isEmpty()) {
896 const qreal from = isContentFlowReversed() ? -position()-displayMarginBeginning-size() : position()-displayMarginBeginning;
897 const qreal to = isContentFlowReversed() ? -position()+displayMarginEnd : position()+size()+displayMarginEnd;
899 FxListItemSG *firstItem =
static_cast<FxListItemSG *>(visibleItems.constFirst());
900 bool fixedCurrent = currentItem && firstItem->item == currentItem->item;
902#if QT_CONFIG(quick_viewtransitions)
904
905 if (transitioner && transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition,
true))
906 resetFirstItemPosition(isContentFlowReversed() ? -firstItem->position()-firstItem->size() : firstItem->position());
909 firstVisibleItemPosition = firstItem->position();
910 qreal sum = firstItem->size();
911 qreal pos = firstItem->position() + firstItem->size() + spacing;
912 firstItem->setVisible(firstItem->endPosition() >= from && firstItem->position() <= to);
917 firstItem->setPosition(firstItem->position());
919 for (
int i=1; i < visibleItems.size(); ++i) {
920 FxListItemSG *item =
static_cast<FxListItemSG*>(visibleItems.at(i));
921 if (item->index >= fromModelIndex) {
922 item->setPosition(pos);
923 item->setVisible(item->endPosition() >= from && item->position() <= to);
925 pos += item->size() + spacing;
927 fixedCurrent = fixedCurrent || (currentItem && item->item == currentItem->item);
929 averageSize = qRound(sum / visibleItems.size());
932 if (currentIndex >= 0 && currentItem && !fixedCurrent)
933 static_cast<FxListItemSG*>(currentItem)->setPosition(positionAt(currentIndex));
990 bool changed =
false;
992 if (trackedItem == highlight.get())
993 trackedItem =
nullptr;
996 highlightPosAnimator.reset();
997 highlightWidthAnimator.reset();
998 highlightHeightAnimator.reset();
999 highlightPosAnimator =
nullptr;
1000 highlightWidthAnimator =
nullptr;
1001 highlightHeightAnimator =
nullptr;
1009 Q_Q(QQuickListView);
1011 QQuickItem *item = createHighlightItem();
1013 std::unique_ptr<FxListItemSG> newHighlight
1014 = std::make_unique<FxListItemSG>(item, q,
true);
1015 newHighlight->trackGeometry(
true);
1017 if (autoHighlight) {
1018 newHighlight->setSize(
static_cast<FxListItemSG*>(currentItem)->itemSize());
1019 newHighlight->setPosition(
static_cast<FxListItemSG*>(currentItem)->itemPosition());
1021 const QLatin1String posProp(orient == QQuickListView::Vertical ?
"y" :
"x");
1022 highlightPosAnimator = std::make_unique<QSmoothedAnimation>();
1023 highlightPosAnimator->target = QQmlProperty(item, posProp);
1024 highlightPosAnimator->velocity = highlightMoveVelocity;
1025 highlightPosAnimator->userDuration = highlightMoveDuration;
1027 highlightWidthAnimator = std::make_unique<QSmoothedAnimation>();
1028 highlightWidthAnimator->velocity = highlightResizeVelocity;
1029 highlightWidthAnimator->userDuration = highlightResizeDuration;
1030 highlightWidthAnimator->target = QQmlProperty(item, QStringLiteral(
"width"));
1032 highlightHeightAnimator = std::make_unique<QSmoothedAnimation>();
1033 highlightHeightAnimator->velocity = highlightResizeVelocity;
1034 highlightHeightAnimator->userDuration = highlightResizeDuration;
1035 highlightHeightAnimator->target = QQmlProperty(item, QStringLiteral(
"height"));
1037 highlight = std::move(newHighlight);
1042 emit q->highlightItemChanged();
1096 Q_Q(QQuickListView);
1097 QQuickItem *sectionItem =
nullptr;
1104 sectionItem->setVisible(
true);
1105 QQmlContext *context = QQmlEngine::contextForObject(sectionItem)->parentContext();
1106 setSectionHelper(context, sectionItem, section);
1108 QQmlComponent* delegate = sectionCriteria->delegate();
1109 const bool reuseExistingContext = delegate->isBound();
1110 auto delegatePriv = QQmlComponentPrivate::get(delegate);
1111 QQmlPropertyCache::ConstPtr rootPropertyCache;
1113 QQmlContext *creationContext = sectionCriteria->delegate()->creationContext();
1114 auto baseContext = creationContext ? creationContext : qmlContext(q);
1116 QQmlContext *context = reuseExistingContext ? baseContext :
new QQmlContext(baseContext);
1117 QObject *nobj = delegate->beginCreate(context);
1119 if (delegatePriv->hadTopLevelRequiredProperties()) {
1120 delegate->setInitialProperties(nobj, {{QLatin1String(
"section"), section}});
1121 }
else if (!reuseExistingContext) {
1122 context->setContextProperty(QLatin1String(
"section"), section);
1124 if (!reuseExistingContext)
1125 QQml_setParent_noEvent(context, nobj);
1126 sectionItem = qobject_cast<QQuickItem *>(nobj);
1130 if (qFuzzyIsNull(sectionItem->z()))
1131 sectionItem->setZ(2);
1132 QQml_setParent_noEvent(sectionItem, contentItem);
1133 sectionItem->setParentItem(contentItem);
1136 auto *attached =
static_cast<QQuickListViewAttached*>(qmlAttachedPropertiesObject<QQuickListView>(sectionItem));
1137 attached->setView(q);
1138 }
else if (!reuseExistingContext) {
1141 sectionCriteria->delegate()->completeCreate();
1145 QQuickItemPrivate::get(sectionItem)->addItemChangeListener(
this, QQuickItemPrivate::Geometry);
1255 if (!sectionCriteria || !sectionCriteria->delegate()
1256 || (!sectionCriteria->labelPositioning() && !currentSectionItem && !nextSectionItem))
1260 qreal viewPos = isFlowReversed ? -position()-size() : position();
1261 qreal startPos = hasStickyHeader() ? header->endPosition() : viewPos;
1262 qreal endPos = hasStickyFooter() ? footer->position() : viewPos + size();
1264 QQuickItem *sectionItem =
nullptr;
1265 QQuickItem *lastSectionItem =
nullptr;
1267 while (index < visibleItems.size()) {
1268 if (QQuickItem *section =
static_cast<FxListItemSG *>(visibleItems.at(index))->section()) {
1271 qreal sectionPos = orient == QQuickListView::Vertical ? section->y() : section->x();
1272 qreal sectionSize = orient == QQuickListView::Vertical ? section->height() : section->width();
1274 if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
1275 visTop = isFlowReversed ? -sectionPos-sectionSize >= startPos : sectionPos >= startPos;
1277 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd)
1278 visBot = isFlowReversed ? -sectionPos <= endPos : sectionPos + sectionSize < endPos;
1279 section->setVisible(visBot && visTop);
1280 if (visTop && !sectionItem)
1281 sectionItem = section;
1282 if (isFlowReversed) {
1283 if (-sectionPos <= endPos)
1284 lastSectionItem = section;
1286 if (sectionPos + sectionSize < endPos)
1287 lastSectionItem = section;
1294 if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart && isValid() && visibleItems.size()) {
1297 }
else if (QString::compare(currentStickySection, currentSection, Qt::CaseInsensitive)) {
1298 QQmlContext *context = QQmlEngine::contextForObject(currentSectionItem)->parentContext();
1301 currentStickySection = currentSection;
1305 qreal sectionSize = orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
1306 bool atBeginning = orient == QQuickListView::Vertical ? (isBottomToTop() ? vData.atEnd : vData.atBeginning) : (isRightToLeft() ? hData.atEnd : hData.atBeginning);
1308 currentSectionItem->setVisible(!atBeginning && (!header || hasStickyHeader() || header->endPosition() < viewPos));
1309 qreal pos = isFlowReversed ? position() + size() - sectionSize : startPos;
1311 pos = isFlowReversed ? qMin(-header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
1313 qreal sectionPos = orient == QQuickListView::Vertical ? sectionItem->y() : sectionItem->x();
1314 pos = isFlowReversed ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize);
1317 pos = isFlowReversed ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
1318 if (orient == QQuickListView::Vertical)
1328 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd && isValid() && visibleItems.size()) {
1331 }
else if (QString::compare(nextStickySection, nextSection, Qt::CaseInsensitive)) {
1332 QQmlContext *context = QQmlEngine::contextForObject(nextSectionItem)->parentContext();
1335 nextStickySection = nextSection;
1339 qreal sectionSize = orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1341 qreal pos = isFlowReversed ? position() : endPos - sectionSize;
1343 pos = isFlowReversed ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
1344 if (lastSectionItem) {
1345 qreal sectionPos = orient == QQuickListView::Vertical ? lastSectionItem->y() : lastSectionItem->x();
1346 pos = isFlowReversed ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize);
1349 pos = isFlowReversed ? qMin(-header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
1350 if (orient == QQuickListView::Vertical)
1404 Q_Q(QQuickListView);
1405 if (!sectionCriteria || visibleItems.isEmpty()) {
1406 if (!currentSection.isEmpty()) {
1407 currentSection.clear();
1408 emit q->currentSectionChanged();
1412 bool inlineSections = sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels;
1413 qreal viewPos = isContentFlowReversed() ? -position()-size() : position();
1414 qreal startPos = hasStickyHeader() ? header->endPosition() : viewPos;
1416 int modelIndex = visibleIndex;
1417 while (index < visibleItems.size()) {
1418 FxViewItem *item = visibleItems.at(index);
1419 if (item->endPosition() > startPos)
1421 if (item->index != -1)
1422 modelIndex = item->index;
1426 QString newSection = currentSection;
1427 if (index < visibleItems.size())
1428 newSection = visibleItems.at(index)->attached->section();
1430 newSection = (*visibleItems.constBegin())->attached->section();
1431 if (newSection != currentSection) {
1432 currentSection = newSection;
1434 emit q->currentSectionChanged();
1437 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd) {
1442 QString lastSection = currentSection;
1443 qreal endPos = hasStickyFooter() ? footer->position() : viewPos + size();
1444 if (nextSectionItem && !inlineSections)
1445 endPos -= orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1446 while (index < visibleItems.size()) {
1447 FxListItemSG *listItem =
static_cast<FxListItemSG *>(visibleItems.at(index));
1448 if (listItem->itemPosition() >= endPos)
1450 if (listItem->index != -1)
1451 modelIndex = listItem->index;
1452 lastSection = listItem->attached->section();
1456 if (lastVisibleSection != lastSection) {
1457 nextSection = QString();
1458 lastVisibleSection = lastSection;
1459 for (
int i = modelIndex; i < itemCount; ++i) {
1460 QString section = sectionAt(i);
1461 if (section != lastSection) {
1462 nextSection = section;
1594 Q_Q(QQuickListView);
1595 bool created =
false;
1597 QQuickItem *item = createComponentItem(headerComponent, 1.0);
1600 header =
new FxListItemSG(item, q,
true);
1601 header->trackGeometry(
true);
1605 FxListItemSG *listItem =
static_cast<FxListItemSG*>(header);
1606 if (headerPositioning == QQuickListView::OverlayHeader) {
1608 }
else if (visibleItems.size()) {
1609 const bool fixingUp = (orient == QQuickListView::Vertical ? vData : hData).fixingUp;
1610 if (headerPositioning == QQuickListView::PullBackHeader) {
1611 qreal headerPosition = listItem->position();
1614 if (fixingUp && !headerNeedsSeparateFixup)
1615 headerPosition = viewPos - headerSize();
1618 qreal clampedPos = qMax(originPosition() - headerSize(), qMin(headerPosition, lastPosition() - size()));
1619 listItem->setPosition(qBound(viewPos - headerSize(), clampedPos, viewPos),
false,
false);
1621 qreal startPos = originPosition();
1622 if (visibleIndex == 0) {
1623 listItem->setPosition(startPos - headerSize(),
false,
false);
1625 if (position() <= startPos || listItem->position() > startPos - headerSize())
1626 listItem->setPosition(startPos - headerSize(),
false,
false);
1630 listItem->setPosition(-headerSize(),
false,
false);
1634 emit q->headerItemChanged();
1656 const QRectF &oldGeometry)
1658 Q_Q(QQuickListView);
1660 QQuickItemViewPrivate::itemGeometryChanged(item, change, oldGeometry);
1661 if (!q->isComponentComplete())
1664 if (currentItem && currentItem->item == item) {
1666 const qreal pos = position();
1667 const qreal sz = size();
1668 const qreal from = contentFlowReversed ? -pos - displayMarginBeginning - sz : pos - displayMarginBeginning;
1669 const qreal to = contentFlowReversed ? -pos + displayMarginEnd : pos + sz + displayMarginEnd;
1670 QQuickItemPrivate::get(currentItem->item)->setCulled(currentItem->endPosition() < from || currentItem->position() > to);
1673 if (item != contentItem && (!highlight || item != highlight->item)) {
1674 if ((orient == QQuickListView::Vertical && change.heightChange())
1675 || (orient == QQuickListView::Horizontal && change.widthChange())) {
1679 if (visibleItems.size() && item == visibleItems.constFirst()->item) {
1680 FxListItemSG *listItem =
static_cast<FxListItemSG*>(visibleItems.constFirst());
1681#if QT_CONFIG(quick_viewtransitions)
1682 if (listItem->transitionScheduledOrRunning())
1685 if (orient == QQuickListView::Vertical) {
1686 const qreal oldItemEndPosition = verticalLayoutDirection == QQuickItemView::BottomToTop ? -oldGeometry.y() : oldGeometry.y() + oldGeometry.height();
1687 const qreal heightDiff = item->height() - oldGeometry.height();
1688 if (verticalLayoutDirection == QQuickListView::TopToBottom && oldItemEndPosition < q->contentY())
1689 listItem->setPosition(listItem->position() - heightDiff,
true);
1690 else if (verticalLayoutDirection == QQuickListView::BottomToTop && oldItemEndPosition > q->contentY())
1691 listItem->setPosition(listItem->position() + heightDiff,
true);
1693 const qreal oldItemEndPosition = q->effectiveLayoutDirection() == Qt::RightToLeft ? -oldGeometry.x() : oldGeometry.x() + oldGeometry.width();
1694 const qreal widthDiff = item->width() - oldGeometry.width();
1695 if (q->effectiveLayoutDirection() == Qt::LeftToRight && oldItemEndPosition < q->contentX())
1696 listItem->setPosition(listItem->position() - widthDiff,
true);
1697 else if (q->effectiveLayoutDirection() == Qt::RightToLeft && oldItemEndPosition > q->contentX())
1698 listItem->setPosition(listItem->position() + widthDiff,
true);
1701 forceLayoutPolish();
1717 if (orient == QQuickListView::Horizontal && &data == &vData) {
1718 if (flickableDirection != QQuickFlickable::HorizontalFlick)
1719 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1721 }
else if (orient == QQuickListView::Vertical && &data == &hData) {
1722 if (flickableDirection != QQuickFlickable::VerticalFlick)
1723 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1728 if (visibleItems.size() == 0)
1732 fixupMode = moveReason == Mouse ? fixupMode : Immediate;
1733 bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
1735 qreal viewPos = isContentFlowReversed() ? -position()-size() : position();
1737 if (snapMode != QQuickListView::NoSnap && moveReason != QQuickListViewPrivate::SetIndex) {
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754 qreal tempPosition = isContentFlowReversed() ? -position()-size() : position();
1755 if (snapMode == QQuickListView::SnapOneItem && moveReason == Mouse) {
1757 qreal dist = data.move.value() - data.pressPos;
1760 bias = averageSize/2;
1762 bias = -averageSize/2;
1763 if (isContentFlowReversed())
1765 tempPosition -= bias;
1768 qreal snapOffset = 0;
1769 qreal overlayHeaderOffset = 0;
1770 bool isHeaderWithinBounds =
false;
1772 qreal visiblePartOfHeader = header->position() + header->size() - tempPosition;
1773 isHeaderWithinBounds = visiblePartOfHeader > 0;
1774 switch (headerPositioning) {
1775 case QQuickListView::OverlayHeader:
1776 snapOffset = header->size();
1777 overlayHeaderOffset = header->size();
1779 case QQuickListView::InlineHeader:
1780 if (isHeaderWithinBounds && tempPosition < originPosition())
1784 snapOffset = header->size() / 2;
1786 case QQuickListView::PullBackHeader:
1788 if (qFuzzyCompare(header->position(), tempPosition)) {
1790 snapOffset = header->size();
1794 snapOffset = header->size();
1795 overlayHeaderOffset = header->size();
1804 if (strictHighlightRange)
1807 FxViewItem *topItem =
nullptr;
1808 FxViewItem *bottomItem =
nullptr;
1810 topItem = visibleItem(snapResizeTargetIndex);
1811 bottomItem = topItem;
1814 topItem = snapItemAt(tempPosition + snapOffset + highlightRangeStart);
1816 bottomItem = snapItemAt(tempPosition + snapOffset + highlightRangeEnd);
1817 if (strictHighlightRange && currentItem) {
1819 if (!topItem || (topItem->index != currentIndex && fixupMode == Immediate))
1820 topItem = currentItem;
1821 if (!bottomItem || (bottomItem->index != currentIndex && fixupMode == Immediate))
1822 bottomItem = currentItem;
1826 bool isInBounds = -position() > maxExtent && -position() <= minExtent;
1828 if (header && !topItem && isInBounds) {
1830 switch (headerPositioning) {
1831 case QQuickListView::OverlayHeader:
1832 pos = startPosition() - overlayHeaderOffset;
1834 case QQuickListView::InlineHeader:
1835 pos = isContentFlowReversed() ? header->size() - size() : header->position();
1837 case QQuickListView::PullBackHeader:
1838 pos = isContentFlowReversed() ? -size() : startPosition();
1841 }
else if (topItem && (isInBounds || strictHighlightRange)) {
1842 if (topItem->index == 0 && header && !hasStickyHeader() && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) {
1843 pos = isContentFlowReversed() ? -header->position() + highlightRangeStart - size() : (header->position() - highlightRangeStart + header->size());
1845 if (header && headerPositioning == QQuickListView::PullBackHeader) {
1848 if (qFuzzyCompare(tempPosition, header->position())) {
1850 if (isContentFlowReversed())
1851 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + snapOffset;
1853 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - snapOffset;
1860 if (isContentFlowReversed())
1861 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + headerSize();
1863 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - headerSize();
1867 if (isContentFlowReversed())
1868 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size();
1870 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart;
1881 pos = qBound(-minExtent, pos, -maxExtent);
1882 desiredViewportPosition = isContentFlowReversed() ? -pos - size() : pos;
1884 FxListItemSG *headerItem =
static_cast<FxListItemSG*>(header);
1885 fixupHeaderPosition = headerItem->position();
1888 QObjectPrivate::connect(&timeline, &QQuickTimeLine::updated,
this, &QQuickListViewPrivate::fixupHeader);
1889 QObjectPrivate::connect(&timeline, &QQuickTimeLine::completed,
this, &QQuickListViewPrivate::fixupHeaderCompleted);
1892 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + overlayHeaderOffset;
1894 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - overlayHeaderOffset;
1897 }
else if (bottomItem && isInBounds) {
1898 if (isContentFlowReversed())
1899 pos = -
static_cast<FxListItemSG*>(bottomItem)->itemPosition() + highlightRangeEnd - size() + overlayHeaderOffset;
1901 pos =
static_cast<FxListItemSG*>(bottomItem)->itemPosition() - highlightRangeEnd - overlayHeaderOffset;
1903 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1909 && (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
1910 && currentSectionItem) {
1911 auto sectionSize = (orient == QQuickListView::Vertical) ? currentSectionItem->height()
1912 : currentSectionItem->width();
1913 if (isContentFlowReversed())
1919 pos = qBound(-minExtent, pos, -maxExtent);
1921 qreal dist = qAbs(data.move + pos);
1926 timeline.reset(data.move);
1927 if (fixupMode != Immediate) {
1928 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1929 data.fixingUp =
true;
1931 timeline.set(data.move, -pos);
1933 vTime = timeline.time();
1935 }
else if (currentItem && strictHighlightRange && moveReason != QQuickListViewPrivate::SetIndex) {
1937 qreal pos =
static_cast<FxListItemSG*>(currentItem)->itemPosition();
1938 if (viewPos < pos +
static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd)
1939 viewPos = pos +
static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd;
1940 if (viewPos > pos - highlightRangeStart)
1941 viewPos = pos - highlightRangeStart;
1942 if (isContentFlowReversed())
1943 viewPos = -viewPos-size();
1945 timeline.reset(data.move);
1946 if (viewPos != position()) {
1947 if (fixupMode != Immediate) {
1948 if (fixupMode == ExtentChanged && data.fixingUp)
1949 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::OutQuad), fixupDuration/2);
1951 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1952 data.fixingUp =
true;
1954 timeline.set(data.move, -viewPos);
1957 vTime = timeline.time();
1959 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1961 data.inOvershoot =
false;
1966 QQuickTimeLineCallback::Callback fixupCallback, QEvent::Type eventType, qreal velocity)
1968 data.fixingUp =
false;
1970 if ((!haveHighlightRange || highlightRange != QQuickListView::StrictlyEnforceRange) && snapMode == QQuickListView::NoSnap) {
1972 return QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, eventType, velocity);
1974 qreal maxDistance = 0;
1975 const qreal dataValue =
1980 if (data.move.value() < minExtent) {
1981 if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1983 qreal bias = averageSize / 2 + 1 - (pressed ? data.pressPos : 0);
1984 if (isContentFlowReversed())
1986 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) - bias) + highlightRangeStart;
1987 maxDistance = qAbs(data.flickTarget - data.move.value());
1988 velocity = maxVelocity;
1990 maxDistance = qAbs(minExtent - data.move.value());
1993 if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
1994 data.flickTarget = minExtent;
1996 if (data.move.value() > maxExtent) {
1997 if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1999 qreal bias = averageSize / 2 + 1 - (pressed ? data.pressPos : 0);
2000 if (isContentFlowReversed())
2003 -snapPosAt(-(dataValue - highlightRangeStart) + bias) + highlightRangeStart;
2004 maxDistance = qAbs(data.flickTarget - data.move.value());
2005 velocity = -maxVelocity;
2007 maxDistance = qAbs(maxExtent - data.move.value());
2010 if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
2011 data.flickTarget = maxExtent;
2013 bool overShoot = boundsBehavior & QQuickFlickable::OvershootBounds;
2014 if (maxDistance > 0 || overShoot) {
2020 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
2026 if (!hData.flicking && !vData.flicking) {
2028 qreal accel = eventType == QEvent::Wheel ? wheelDeceleration : deceleration;
2030 overshootDist = 0.0;
2032 qreal dist = v2 / (accel * 2.0) + averageSize/4;
2033 if (maxDistance > 0)
2034 dist = qMin(dist, maxDistance);
2037 if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickListView::SnapOneItem) {
2038 if (snapMode != QQuickListView::SnapOneItem) {
2039 qreal distTemp = isContentFlowReversed() ? -dist : dist;
2040 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + distTemp) + highlightRangeStart;
2044 if (data.flickTarget > minExtent) {
2045 overshootDist = overShootDistance(vSize);
2046 data.flickTarget += overshootDist;
2047 }
else if (data.flickTarget < maxExtent) {
2048 overshootDist = overShootDistance(vSize);
2049 data.flickTarget -= overshootDist;
2052 qreal adjDist = -data.flickTarget + data.move.value();
2053 if (qAbs(adjDist) > qAbs(dist)) {
2055 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
2064 accel = v2 / (2.0f * qAbs(dist));
2065 }
else if (overShoot) {
2066 data.flickTarget = data.move.value() - dist;
2067 if (data.flickTarget > minExtent) {
2068 overshootDist = overShootDistance(vSize);
2069 data.flickTarget += overshootDist;
2070 }
else if (data.flickTarget < maxExtent) {
2071 overshootDist = overShootDistance(vSize);
2072 data.flickTarget -= overshootDist;
2075 timeline.reset(data.move);
2076 timeline.accel(data.move, v, accel, maxDistance + overshootDist);
2077 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback,
this));
2082 qreal newtarget = data.flickTarget;
2083 if (snapMode != QQuickListView::NoSnap || highlightRange == QQuickListView::StrictlyEnforceRange) {
2084 qreal tempFlickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget;
2085 newtarget = -snapPosAt(-(tempFlickTarget - highlightRangeStart)) + highlightRangeStart;
2086 newtarget = isContentFlowReversed() ? -newtarget+size() : newtarget;
2088 if (velocity < 0 && newtarget <= maxExtent)
2089 newtarget = maxExtent - overshootDist;
2090 else if (velocity > 0 && newtarget >= minExtent)
2091 newtarget = minExtent + overshootDist;
2092 if (newtarget == data.flickTarget) {
2093 if (qAbs(velocity) < _q_MinimumFlickVelocity)
2097 data.flickTarget = newtarget;
2098 qreal dist = -newtarget + data.move.value();
2099 if ((v < 0 && dist < 0) || (v > 0 && dist > 0)) {
2101 timeline.reset(data.move);
2102 fixup(data, minExtent, maxExtent);
2105 timeline.reset(data.move);
2106 timeline.accelDistance(data.move, v, -dist);
2107 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback,
this));
2112 timeline.reset(data.move);
2113 fixup(data, minExtent, maxExtent);
3596void QQuickListView::viewportMoved(Qt::Orientations orient)
3598 Q_D(QQuickListView);
3599 QQuickItemView::viewportMoved(orient);
3601 if (!d->itemCount) {
3602 if (d->hasStickyHeader())
3604 if (d->hasStickyFooter())
3610 if (d->inViewportMoved)
3612 d->inViewportMoved =
true;
3615 if (d->isBottomToTop())
3616 d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
3618 d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
3620 if (d->isRightToLeft())
3621 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
3623 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
3626 d->refillOrLayout();
3629 qreal from = d->isContentFlowReversed() ? -d->position()-d->displayMarginBeginning-d->size() : d->position()-d->displayMarginBeginning;
3630 qreal to = d->isContentFlowReversed() ? -d->position()+d->displayMarginEnd : d->position()+d->size()+d->displayMarginEnd;
3631 for (FxViewItem *item : std::as_const(d->visibleItems)) {
3633 QQuickItemPrivate::get(item->item)->setCulled(item->endPosition() < from || item->position() > to);
3636 QQuickItemPrivate::get(d->currentItem->item)->setCulled(d->currentItem->endPosition() < from || d->currentItem->position() > to);
3638 if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
3639 d->moveReason = QQuickListViewPrivate::Mouse;
3640 if (d->moveReason != QQuickListViewPrivate::SetIndex) {
3641 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
3643 qreal pos = d->highlight->position();
3644 qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
3645 if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
3646 pos = viewPos + d->highlightRangeEnd - d->highlight->size();
3647 if (pos < viewPos + d->highlightRangeStart)
3648 pos = viewPos + d->highlightRangeStart;
3649 if (pos != d->highlight->position()) {
3650 d->highlightPosAnimator->stop();
3651 static_cast<FxListItemSG*>(d->highlight.get())->setPosition(pos);
3653 d->updateHighlight();
3657 if (FxViewItem *snapItem = d->snapItemAt(d->highlight->position())) {
3658 if (snapItem->index >= 0 && snapItem->index != d->currentIndex)
3659 d->updateCurrent(snapItem->index);
3664 if ((d->hData.flicking || d->vData.flicking) && d->correctFlick && !d->inFlickCorrection) {
3665 d->inFlickCorrection =
true;
3668 if (yflick() && !d->vData.inOvershoot) {
3669 if (d->vData.velocity > 0) {
3670 const qreal minY = minYExtent();
3671 if ((minY - d->vData.move.value() < height()/2 || d->vData.flickTarget - d->vData.move.value() < height()/2)
3672 && minY != d->vData.flickTarget)
3673 d->flickY(QEvent::TouchUpdate, -d->vData.smoothVelocity.value());
3674 }
else if (d->vData.velocity < 0) {
3675 const qreal maxY = maxYExtent();
3676 if ((d->vData.move.value() - maxY < height()/2 || d->vData.move.value() - d->vData.flickTarget < height()/2)
3677 && maxY != d->vData.flickTarget)
3678 d->flickY(QEvent::TouchUpdate, -d->vData.smoothVelocity.value());
3682 if (xflick() && !d->hData.inOvershoot) {
3683 if (d->hData.velocity > 0) {
3684 const qreal minX = minXExtent();
3685 if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2)
3686 && minX != d->hData.flickTarget)
3687 d->flickX(QEvent::TouchUpdate, -d->hData.smoothVelocity.value());
3688 }
else if (d->hData.velocity < 0) {
3689 const qreal maxX = maxXExtent();
3690 if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2)
3691 && maxX != d->hData.flickTarget)
3692 d->flickX(QEvent::TouchUpdate, -d->hData.smoothVelocity.value());
3695 d->inFlickCorrection =
false;
3697 if (d->hasStickyHeader())
3699 if (d->hasStickyFooter())
3701 if (d->sectionCriteria) {
3702 d->updateCurrentSection();
3703 d->updateStickySections();
3705 d->inViewportMoved =
false;
3872 Q_Q(QQuickListView);
3873#if !QT_CONFIG(quick_viewtransitions)
3874 Q_UNUSED(movingIntoView)
3876 int modelIndex = change.index;
3877 int count = change.count;
3879 if (q->size().isNull() && visibleItems.isEmpty())
3882 qreal tempPos = isContentFlowReversed() ? -position()-size() : position();
3883 int index = visibleItems.size() ? mapFromModel(modelIndex) : 0;
3884 qreal lastVisiblePos = buffer + displayMarginEnd + tempPos + size();
3887 int i = visibleItems.size() - 1;
3888 while (i > 0 && visibleItems.at(i)->index == -1)
3890 if (i == 0 && visibleItems.constFirst()->index == -1) {
3892 index = visibleItems.size();
3893 }
else if (visibleItems.at(i)->index + 1 == modelIndex
3894 && visibleItems.at(i)->endPosition() <= lastVisiblePos) {
3896 index = visibleItems.size();
3898 if (modelIndex < visibleIndex) {
3900 visibleIndex += count;
3901 for (FxViewItem *item : std::as_const(visibleItems)) {
3902 if (item->index != -1 && item->index >= modelIndex)
3903 item->index += count;
3912 if (visibleItems.size()) {
3913 pos = index < visibleItems.size() ? visibleItems.at(index)->position()
3914 : visibleItems.constLast()->endPosition() + spacing;
3918 for (FxViewItem *item : std::as_const(visibleItems)) {
3919 if (item->index != -1 && item->index >= modelIndex) {
3920 item->index += count;
3921#if QT_CONFIG(quick_viewtransitions)
3922 if (change.isMove())
3923 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition,
false);
3925 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition,
false);
3930 bool visibleAffected =
false;
3931 if (insertResult->visiblePos.isValid() && pos < insertResult->visiblePos) {
3933 int insertionIdx = index;
3934 qreal from = tempPos - displayMarginBeginning - buffer;
3936 if (insertionIdx < visibleIndex) {
3939 insertResult->sizeChangesBeforeVisiblePos += count * (averageSize + spacing);
3943 for (; it.hasNext() && pos >= from; it
.next()) {
3945 FxViewItem *item =
nullptr;
3946 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(it.index))))
3947 item->index = it.index;
3949 item = createItem(it.index, QQmlIncubator::Synchronous);
3955 visibleAffected =
true;
3956 visibleItems.insert(insertionIdx, item);
3957 if (insertionIdx == 0)
3958 insertResult->changedFirstItem =
true;
3959 if (!change.isMove()) {
3960 addedItems->append(item);
3961#if QT_CONFIG(quick_viewtransitions)
3963 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition,
true);
3966 static_cast<FxListItemSG *>(item)->setPosition(pos,
true);
3968 insertResult->sizeChangesBeforeVisiblePos += item->size() + spacing;
3969 pos -= item->size() + spacing;
3974 int firstOkIdx = -1;
3975 for (
int i = 0; i <= insertionIdx && i < visibleItems.size() - 1; i++) {
3976 if (visibleItems.at(i)->index + 1 != visibleItems.at(i + 1)->index) {
3981 for (
int i = 0; i < firstOkIdx; i++) {
3982 FxViewItem *nvItem = visibleItems.takeFirst();
3983 addedItems->removeOne(nvItem);
3989 for (; it.hasNext() && pos <= lastVisiblePos; it
.next()) {
3990 visibleAffected =
true;
3991 FxViewItem *item =
nullptr;
3992 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(it.index))))
3993 item->index = it.index;
3994#if QT_CONFIG(quick_viewtransitions)
3995 bool newItem = !item;
3999 item = createItem(it.index, QQmlIncubator::Synchronous);
4003 releaseItem(item, reusableFlag);
4007 if (index < visibleItems.size())
4008 visibleItems.insert(index, item);
4010 visibleItems.append(item);
4012 insertResult->changedFirstItem =
true;
4013 if (change.isMove()) {
4016#if QT_CONFIG(quick_viewtransitions)
4017 if (newItem && transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition,
true))
4018 movingIntoView->append(MovedItem(item, change.moveKey(item->index)));
4021 addedItems->append(item);
4022#if QT_CONFIG(quick_viewtransitions)
4024 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition,
true);
4027 static_cast<FxListItemSG *>(item)->setPosition(pos,
true);
4029 insertResult->sizeChangesAfterVisiblePos += item->size() + spacing;
4030 pos += item->size() + spacing;
4035 if (0 < index && index < visibleItems.size()) {
4036 FxViewItem *prevItem = visibleItems.at(index - 1);
4037 FxViewItem *item = visibleItems.at(index);
4038 if (prevItem->index != item->index - 1) {
4040#if QT_CONFIG(quick_viewtransitions)
4041 qreal prevPos = prevItem->position();
4043 while (i < visibleItems.size()) {
4044 FxListItemSG *nvItem =
static_cast<FxListItemSG *>(visibleItems.takeLast());
4045 insertResult->sizeChangesAfterVisiblePos -= nvItem->size() + spacing;
4046 addedItems->removeOne(nvItem);
4047#if QT_CONFIG(quick_viewtransitions)
4048 if (nvItem->transitionScheduledOrRunning())
4049 nvItem->setPosition(prevPos + (nvItem->index - prevItem->index) * averageSize);
4057 updateVisibleIndex();
4059 return visibleAffected;