733 qreal itemEnd = visiblePos;
734 if (visibleItems.size()) {
735 visiblePos = (*visibleItems.constBegin())->position();
736 itemEnd = (*(visibleItems.constEnd() - 1))->endPosition() + spacing;
739 int modelIndex = findLastVisibleIndex();
740 bool haveValidItems = modelIndex >= 0;
741 modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
743 if (haveValidItems && (bufferFrom > itemEnd+averageSize+spacing
744 || bufferTo < visiblePos - averageSize - spacing)) {
747 int count = (fillFrom - itemEnd) / (averageSize + spacing);
748 int newModelIdx = qBound(0, modelIndex + count, model->count());
749 count = newModelIdx - modelIndex;
751 releaseVisibleItems(reusableFlag);
752 modelIndex = newModelIdx;
753 visibleIndex = modelIndex;
754 visiblePos = itemEnd + count * (averageSize + spacing);
755 itemEnd = visiblePos;
759 QQmlIncubator::IncubationMode incubationMode = doBuffer ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested;
761 bool changed =
false;
764 while (modelIndex < model->count() && pos <= fillTo) {
765 if (!(item =
static_cast<
FxListItemSG*>(createItem(modelIndex, incubationMode))))
767 qCDebug(lcItemViewDelegateLifecycle) <<
"refill: append item" << modelIndex <<
"pos" << pos <<
"buffer" << doBuffer <<
"item" << (QObject *)(item->item);
768#if QT_CONFIG(quick_viewtransitions)
769 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition,
true))
771 item->setPosition(pos,
true);
773 QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
774 pos += item->size() + spacing;
775 visibleItems.append(item);
780 if (doBuffer && requestedIndex != -1)
783 while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > fillFrom) {
784 if (!(item =
static_cast<
FxListItemSG*>(createItem(visibleIndex-1, incubationMode))))
786 qCDebug(lcItemViewDelegateLifecycle) <<
"refill: prepend item" << visibleIndex-1 <<
"current top pos" << visiblePos <<
"buffer" << doBuffer <<
"item" << (QObject *)(item->item);
788 visiblePos -= item->size() + spacing;
789#if QT_CONFIG(quick_viewtransitions)
790 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition,
true))
792 item->setPosition(visiblePos,
true);
794 QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
795 visibleItems.prepend(item);
799 if (changed && sectionCriteria)
885 if (!visibleItems.isEmpty()) {
886 const qreal from = isContentFlowReversed() ? -position()-displayMarginBeginning-size() : position()-displayMarginBeginning;
887 const qreal to = isContentFlowReversed() ? -position()+displayMarginEnd : position()+size()+displayMarginEnd;
889 FxListItemSG *firstItem =
static_cast<FxListItemSG *>(visibleItems.constFirst());
890 bool fixedCurrent = currentItem && firstItem->item == currentItem->item;
892#if QT_CONFIG(quick_viewtransitions)
894
895 if (transitioner && transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition,
true))
896 resetFirstItemPosition(isContentFlowReversed() ? -firstItem->position()-firstItem->size() : firstItem->position());
899 firstVisibleItemPosition = firstItem->position();
900 qreal sum = firstItem->size();
901 qreal pos = firstItem->position() + firstItem->size() + spacing;
902 firstItem->setVisible(firstItem->endPosition() >= from && firstItem->position() <= to);
907 firstItem->setPosition(firstItem->position());
909 for (
int i=1; i < visibleItems.size(); ++i) {
910 FxListItemSG *item =
static_cast<FxListItemSG*>(visibleItems.at(i));
911 if (item->index >= fromModelIndex) {
912 item->setPosition(pos);
913 item->setVisible(item->endPosition() >= from && item->position() <= to);
915 pos += item->size() + spacing;
917 fixedCurrent = fixedCurrent || (currentItem && item->item == currentItem->item);
919 averageSize = qRound(sum / visibleItems.size());
922 if (currentIndex >= 0 && currentItem && !fixedCurrent)
923 static_cast<FxListItemSG*>(currentItem)->setPosition(positionAt(currentIndex));
980 bool changed =
false;
982 if (trackedItem == highlight.get())
983 trackedItem =
nullptr;
986 highlightPosAnimator.reset();
987 highlightWidthAnimator.reset();
988 highlightHeightAnimator.reset();
989 highlightPosAnimator =
nullptr;
990 highlightWidthAnimator =
nullptr;
991 highlightHeightAnimator =
nullptr;
1001 QQuickItem *item = createHighlightItem();
1003 std::unique_ptr<FxListItemSG> newHighlight
1004 = std::make_unique<FxListItemSG>(item, q,
true);
1005 newHighlight->trackGeometry(
true);
1007 if (autoHighlight) {
1008 newHighlight->setSize(
static_cast<FxListItemSG*>(currentItem)->itemSize());
1009 newHighlight->setPosition(
static_cast<FxListItemSG*>(currentItem)->itemPosition());
1011 const QLatin1String posProp(orient == QQuickListView::Vertical ?
"y" :
"x");
1012 highlightPosAnimator = std::make_unique<QSmoothedAnimation>();
1013 highlightPosAnimator->target = QQmlProperty(item, posProp);
1014 highlightPosAnimator->velocity = highlightMoveVelocity;
1015 highlightPosAnimator->userDuration = highlightMoveDuration;
1017 highlightWidthAnimator = std::make_unique<QSmoothedAnimation>();
1018 highlightWidthAnimator->velocity = highlightResizeVelocity;
1019 highlightWidthAnimator->userDuration = highlightResizeDuration;
1020 highlightWidthAnimator->target = QQmlProperty(item, QStringLiteral(
"width"));
1022 highlightHeightAnimator = std::make_unique<QSmoothedAnimation>();
1023 highlightHeightAnimator->velocity = highlightResizeVelocity;
1024 highlightHeightAnimator->userDuration = highlightResizeDuration;
1025 highlightHeightAnimator->target = QQmlProperty(item, QStringLiteral(
"height"));
1027 highlight = std::move(newHighlight);
1032 emit q->highlightItemChanged();
1086 Q_Q(QQuickListView);
1087 QQuickItem *sectionItem =
nullptr;
1094 sectionItem->setVisible(
true);
1095 QQmlContext *context = QQmlEngine::contextForObject(sectionItem)->parentContext();
1096 setSectionHelper(context, sectionItem, section);
1098 QQmlComponent* delegate = sectionCriteria->delegate();
1099 const bool reuseExistingContext = delegate->isBound();
1100 auto delegatePriv = QQmlComponentPrivate::get(delegate);
1101 QQmlPropertyCache::ConstPtr rootPropertyCache;
1103 QQmlContext *creationContext = sectionCriteria->delegate()->creationContext();
1104 auto baseContext = creationContext ? creationContext : qmlContext(q);
1106 QQmlContext *context = reuseExistingContext ? baseContext :
new QQmlContext(baseContext);
1107 QObject *nobj = delegate->beginCreate(context);
1109 if (delegatePriv->hadTopLevelRequiredProperties()) {
1110 delegate->setInitialProperties(nobj, {{QLatin1String(
"section"), section}});
1111 }
else if (!reuseExistingContext) {
1112 context->setContextProperty(QLatin1String(
"section"), section);
1114 if (!reuseExistingContext)
1115 QQml_setParent_noEvent(context, nobj);
1116 sectionItem = qobject_cast<QQuickItem *>(nobj);
1120 if (qFuzzyIsNull(sectionItem->z()))
1121 sectionItem->setZ(2);
1122 QQml_setParent_noEvent(sectionItem, contentItem);
1123 sectionItem->setParentItem(contentItem);
1126 auto *attached =
static_cast<QQuickListViewAttached*>(qmlAttachedPropertiesObject<QQuickListView>(sectionItem));
1127 attached->setView(q);
1128 }
else if (!reuseExistingContext) {
1131 sectionCriteria->delegate()->completeCreate();
1135 QQuickItemPrivate::get(sectionItem)->addItemChangeListener(
this, QQuickItemPrivate::Geometry);
1245 if (!sectionCriteria || !sectionCriteria->delegate()
1246 || (!sectionCriteria->labelPositioning() && !currentSectionItem && !nextSectionItem))
1250 qreal viewPos = isFlowReversed ? -position()-size() : position();
1251 qreal startPos = hasStickyHeader() ? header->endPosition() : viewPos;
1252 qreal endPos = hasStickyFooter() ? footer->position() : viewPos + size();
1254 QQuickItem *sectionItem =
nullptr;
1255 QQuickItem *lastSectionItem =
nullptr;
1257 while (index < visibleItems.size()) {
1258 if (QQuickItem *section =
static_cast<FxListItemSG *>(visibleItems.at(index))->section()) {
1261 qreal sectionPos = orient == QQuickListView::Vertical ? section->y() : section->x();
1262 qreal sectionSize = orient == QQuickListView::Vertical ? section->height() : section->width();
1264 if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
1265 visTop = isFlowReversed ? -sectionPos-sectionSize >= startPos : sectionPos >= startPos;
1267 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd)
1268 visBot = isFlowReversed ? -sectionPos <= endPos : sectionPos + sectionSize < endPos;
1269 section->setVisible(visBot && visTop);
1270 if (visTop && !sectionItem)
1271 sectionItem = section;
1272 if (isFlowReversed) {
1273 if (-sectionPos <= endPos)
1274 lastSectionItem = section;
1276 if (sectionPos + sectionSize < endPos)
1277 lastSectionItem = section;
1284 if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart && isValid() && visibleItems.size()) {
1286 currentSectionItem = getSectionItem(currentSection);
1287 }
else if (QString::compare(currentStickySection, currentSection, Qt::CaseInsensitive)) {
1288 QQmlContext *context = QQmlEngine::contextForObject(currentSectionItem)->parentContext();
1291 currentStickySection = currentSection;
1295 qreal sectionSize = orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
1296 bool atBeginning = orient == QQuickListView::Vertical ? (isBottomToTop() ? vData.atEnd : vData.atBeginning) : (isRightToLeft() ? hData.atEnd : hData.atBeginning);
1298 currentSectionItem->setVisible(!atBeginning && (!header || hasStickyHeader() || header->endPosition() < viewPos));
1299 qreal pos = isFlowReversed ? position() + size() - sectionSize : startPos;
1301 pos = isFlowReversed ? qMin(-header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
1303 qreal sectionPos = orient == QQuickListView::Vertical ? sectionItem->y() : sectionItem->x();
1304 pos = isFlowReversed ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize);
1307 pos = isFlowReversed ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
1308 if (orient == QQuickListView::Vertical)
1318 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd && isValid() && visibleItems.size()) {
1320 nextSectionItem = getSectionItem(nextSection);
1321 }
else if (QString::compare(nextStickySection, nextSection, Qt::CaseInsensitive)) {
1322 QQmlContext *context = QQmlEngine::contextForObject(nextSectionItem)->parentContext();
1325 nextStickySection = nextSection;
1329 qreal sectionSize = orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1331 qreal pos = isFlowReversed ? position() : endPos - sectionSize;
1333 pos = isFlowReversed ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
1334 if (lastSectionItem) {
1335 qreal sectionPos = orient == QQuickListView::Vertical ? lastSectionItem->y() : lastSectionItem->x();
1336 pos = isFlowReversed ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize);
1339 pos = isFlowReversed ? qMin(-header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
1340 if (orient == QQuickListView::Vertical)
1394 Q_Q(QQuickListView);
1395 if (!sectionCriteria || visibleItems.isEmpty()) {
1396 if (!currentSection.isEmpty()) {
1397 currentSection.clear();
1398 emit q->currentSectionChanged();
1402 bool inlineSections = sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels;
1403 qreal viewPos = isContentFlowReversed() ? -position()-size() : position();
1404 qreal startPos = hasStickyHeader() ? header->endPosition() : viewPos;
1406 int modelIndex = visibleIndex;
1407 while (index < visibleItems.size()) {
1408 FxViewItem *item = visibleItems.at(index);
1409 if (item->endPosition() > startPos)
1411 if (item->index != -1)
1412 modelIndex = item->index;
1416 QString newSection = currentSection;
1417 if (index < visibleItems.size())
1418 newSection = visibleItems.at(index)->attached->section();
1420 newSection = (*visibleItems.constBegin())->attached->section();
1421 if (newSection != currentSection) {
1422 currentSection = newSection;
1424 emit q->currentSectionChanged();
1427 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd) {
1432 QString lastSection = currentSection;
1433 qreal endPos = hasStickyFooter() ? footer->position() : viewPos + size();
1434 if (nextSectionItem && !inlineSections)
1435 endPos -= orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1436 while (index < visibleItems.size()) {
1437 FxListItemSG *listItem =
static_cast<FxListItemSG *>(visibleItems.at(index));
1438 if (listItem->itemPosition() >= endPos)
1440 if (listItem->index != -1)
1441 modelIndex = listItem->index;
1442 lastSection = listItem->attached->section();
1446 if (lastVisibleSection != lastSection) {
1447 nextSection = QString();
1448 lastVisibleSection = lastSection;
1449 for (
int i = modelIndex; i < itemCount; ++i) {
1450 QString section = sectionAt(i);
1451 if (section != lastSection) {
1452 nextSection = section;
1584 Q_Q(QQuickListView);
1585 bool created =
false;
1587 QQuickItem *item = createComponentItem(headerComponent, 1.0);
1590 header =
new FxListItemSG(item, q,
true);
1591 header->trackGeometry(
true);
1595 FxListItemSG *listItem =
static_cast<FxListItemSG*>(header);
1596 if (headerPositioning == QQuickListView::OverlayHeader) {
1598 }
else if (visibleItems.size()) {
1599 const bool fixingUp = (orient == QQuickListView::Vertical ? vData : hData).fixingUp;
1600 if (headerPositioning == QQuickListView::PullBackHeader) {
1601 qreal headerPosition = listItem->position();
1604 if (fixingUp && !headerNeedsSeparateFixup)
1605 headerPosition = viewPos - headerSize();
1608 qreal clampedPos = qMax(originPosition() - headerSize(), qMin(headerPosition, lastPosition() - size()));
1609 listItem->setPosition(qBound(viewPos - headerSize(), clampedPos, viewPos),
false,
false);
1611 qreal startPos = originPosition();
1612 if (visibleIndex == 0) {
1613 listItem->setPosition(startPos - headerSize(),
false,
false);
1615 if (position() <= startPos || listItem->position() > startPos - headerSize())
1616 listItem->setPosition(startPos - headerSize(),
false,
false);
1620 listItem->setPosition(-headerSize(),
false,
false);
1624 emit q->headerItemChanged();
1646 const QRectF &oldGeometry)
1648 Q_Q(QQuickListView);
1650 QQuickItemViewPrivate::itemGeometryChanged(item, change, oldGeometry);
1651 if (!q->isComponentComplete())
1654 if (currentItem && currentItem->item == item) {
1656 const qreal pos = position();
1657 const qreal sz = size();
1658 const qreal from = contentFlowReversed ? -pos - displayMarginBeginning - sz : pos - displayMarginBeginning;
1659 const qreal to = contentFlowReversed ? -pos + displayMarginEnd : pos + sz + displayMarginEnd;
1660 QQuickItemPrivate::get(currentItem->item)->setCulled(currentItem->endPosition() < from || currentItem->position() > to);
1663 if (item != contentItem && (!highlight || item != highlight->item)) {
1664 if ((orient == QQuickListView::Vertical && change.heightChange())
1665 || (orient == QQuickListView::Horizontal && change.widthChange())) {
1669 if (visibleItems.size() && item == visibleItems.constFirst()->item) {
1670 FxListItemSG *listItem =
static_cast<FxListItemSG*>(visibleItems.constFirst());
1671#if QT_CONFIG(quick_viewtransitions)
1672 if (listItem->transitionScheduledOrRunning())
1675 if (orient == QQuickListView::Vertical) {
1676 const qreal oldItemEndPosition = verticalLayoutDirection == QQuickItemView::BottomToTop ? -oldGeometry.y() : oldGeometry.y() + oldGeometry.height();
1677 const qreal heightDiff = item->height() - oldGeometry.height();
1678 if (verticalLayoutDirection == QQuickListView::TopToBottom && oldItemEndPosition < q->contentY())
1679 listItem->setPosition(listItem->position() - heightDiff,
true);
1680 else if (verticalLayoutDirection == QQuickListView::BottomToTop && oldItemEndPosition > q->contentY())
1681 listItem->setPosition(listItem->position() + heightDiff,
true);
1683 const qreal oldItemEndPosition = q->effectiveLayoutDirection() == Qt::RightToLeft ? -oldGeometry.x() : oldGeometry.x() + oldGeometry.width();
1684 const qreal widthDiff = item->width() - oldGeometry.width();
1685 if (q->effectiveLayoutDirection() == Qt::LeftToRight && oldItemEndPosition < q->contentX())
1686 listItem->setPosition(listItem->position() - widthDiff,
true);
1687 else if (q->effectiveLayoutDirection() == Qt::RightToLeft && oldItemEndPosition > q->contentX())
1688 listItem->setPosition(listItem->position() + widthDiff,
true);
1691 forceLayoutPolish();
1707 if (orient == QQuickListView::Horizontal && &data == &vData) {
1708 if (flickableDirection != QQuickFlickable::HorizontalFlick)
1709 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1711 }
else if (orient == QQuickListView::Vertical && &data == &hData) {
1712 if (flickableDirection != QQuickFlickable::VerticalFlick)
1713 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1718 if (visibleItems.size() == 0)
1722 fixupMode = moveReason == Mouse ? fixupMode : Immediate;
1723 bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
1725 qreal viewPos = isContentFlowReversed() ? -position()-size() : position();
1727 if (snapMode != QQuickListView::NoSnap && moveReason != QQuickListViewPrivate::SetIndex) {
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744 qreal tempPosition = isContentFlowReversed() ? -position()-size() : position();
1745 if (snapMode == QQuickListView::SnapOneItem && moveReason == Mouse) {
1747 qreal dist = data.move.value() - data.pressPos;
1750 bias = averageSize/2;
1752 bias = -averageSize/2;
1753 if (isContentFlowReversed())
1755 tempPosition -= bias;
1758 qreal snapOffset = 0;
1759 qreal overlayHeaderOffset = 0;
1760 bool isHeaderWithinBounds =
false;
1762 qreal visiblePartOfHeader = header->position() + header->size() - tempPosition;
1763 isHeaderWithinBounds = visiblePartOfHeader > 0;
1764 switch (headerPositioning) {
1765 case QQuickListView::OverlayHeader:
1766 snapOffset = header->size();
1767 overlayHeaderOffset = header->size();
1769 case QQuickListView::InlineHeader:
1770 if (isHeaderWithinBounds && tempPosition < originPosition())
1774 snapOffset = header->size() / 2;
1776 case QQuickListView::PullBackHeader:
1777 desiredHeaderVisible = visiblePartOfHeader > header->size()/2;
1778 if (qFuzzyCompare(header->position(), tempPosition)) {
1780 snapOffset = header->size();
1784 snapOffset = header->size();
1785 overlayHeaderOffset = header->size();
1794 if (strictHighlightRange)
1797 FxViewItem *topItem =
nullptr;
1798 FxViewItem *bottomItem =
nullptr;
1800 topItem = visibleItem(snapResizeTargetIndex);
1801 bottomItem = topItem;
1804 topItem = snapItemAt(tempPosition + snapOffset + highlightRangeStart);
1806 bottomItem = snapItemAt(tempPosition + snapOffset + highlightRangeEnd);
1807 if (strictHighlightRange && currentItem) {
1809 if (!topItem || (topItem->index != currentIndex && fixupMode == Immediate))
1810 topItem = currentItem;
1811 if (!bottomItem || (bottomItem->index != currentIndex && fixupMode == Immediate))
1812 bottomItem = currentItem;
1816 bool isInBounds = -position() > maxExtent && -position() <= minExtent;
1818 if (header && !topItem && isInBounds) {
1820 switch (headerPositioning) {
1821 case QQuickListView::OverlayHeader:
1822 pos = startPosition() - overlayHeaderOffset;
1824 case QQuickListView::InlineHeader:
1825 pos = isContentFlowReversed() ? header->size() - size() : header->position();
1827 case QQuickListView::PullBackHeader:
1828 pos = isContentFlowReversed() ? -size() : startPosition();
1831 }
else if (topItem && (isInBounds || strictHighlightRange)) {
1832 if (topItem->index == 0 && header && !hasStickyHeader() && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) {
1833 pos = isContentFlowReversed() ? -header->position() + highlightRangeStart - size() : (header->position() - highlightRangeStart + header->size());
1835 if (header && headerPositioning == QQuickListView::PullBackHeader) {
1838 if (qFuzzyCompare(tempPosition, header->position())) {
1840 if (isContentFlowReversed())
1841 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + snapOffset;
1843 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - snapOffset;
1850 if (isContentFlowReversed())
1851 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + headerSize();
1853 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - headerSize();
1857 if (isContentFlowReversed())
1858 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size();
1860 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart;
1871 pos = qBound(-minExtent, pos, -maxExtent);
1872 desiredViewportPosition = isContentFlowReversed() ? -pos - size() : pos;
1874 FxListItemSG *headerItem =
static_cast<FxListItemSG*>(header);
1875 fixupHeaderPosition = headerItem->position();
1878 QObjectPrivate::connect(&timeline, &QQuickTimeLine::updated,
this, &QQuickListViewPrivate::fixupHeader);
1879 QObjectPrivate::connect(&timeline, &QQuickTimeLine::completed,
this, &QQuickListViewPrivate::fixupHeaderCompleted);
1882 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + overlayHeaderOffset;
1884 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - overlayHeaderOffset;
1887 }
else if (bottomItem && isInBounds) {
1888 if (isContentFlowReversed())
1889 pos = -
static_cast<FxListItemSG*>(bottomItem)->itemPosition() + highlightRangeEnd - size() + overlayHeaderOffset;
1891 pos =
static_cast<FxListItemSG*>(bottomItem)->itemPosition() - highlightRangeEnd - overlayHeaderOffset;
1893 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1899 && (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
1900 && currentSectionItem) {
1901 auto sectionSize = (orient == QQuickListView::Vertical) ? currentSectionItem->height()
1902 : currentSectionItem->width();
1903 if (isContentFlowReversed())
1909 pos = qBound(-minExtent, pos, -maxExtent);
1911 qreal dist = qAbs(data.move + pos);
1916 timeline.reset(data.move);
1917 if (fixupMode != Immediate) {
1918 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1919 data.fixingUp =
true;
1921 timeline.set(data.move, -pos);
1923 vTime = timeline.time();
1925 }
else if (currentItem && strictHighlightRange && moveReason != QQuickListViewPrivate::SetIndex) {
1927 qreal pos =
static_cast<FxListItemSG*>(currentItem)->itemPosition();
1928 if (viewPos < pos +
static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd)
1929 viewPos = pos +
static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd;
1930 if (viewPos > pos - highlightRangeStart)
1931 viewPos = pos - highlightRangeStart;
1932 if (isContentFlowReversed())
1933 viewPos = -viewPos-size();
1935 timeline.reset(data.move);
1936 if (viewPos != position()) {
1937 if (fixupMode != Immediate) {
1938 if (fixupMode == ExtentChanged && data.fixingUp)
1939 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::OutQuad), fixupDuration/2);
1941 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1942 data.fixingUp =
true;
1944 timeline.set(data.move, -viewPos);
1947 vTime = timeline.time();
1949 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1951 data.inOvershoot =
false;
1956 QQuickTimeLineCallback::Callback fixupCallback, QEvent::Type eventType, qreal velocity)
1958 data.fixingUp =
false;
1960 if ((!haveHighlightRange || highlightRange != QQuickListView::StrictlyEnforceRange) && snapMode == QQuickListView::NoSnap) {
1962 return QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, eventType, velocity);
1964 qreal maxDistance = 0;
1965 const qreal dataValue =
1970 if (data.move.value() < minExtent) {
1971 if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1973 qreal bias = averageSize / 2 + 1 - (pressed ? data.pressPos : 0);
1974 if (isContentFlowReversed())
1976 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) - bias) + highlightRangeStart;
1977 maxDistance = qAbs(data.flickTarget - data.move.value());
1978 velocity = maxVelocity;
1980 maxDistance = qAbs(minExtent - data.move.value());
1983 if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
1984 data.flickTarget = minExtent;
1986 if (data.move.value() > maxExtent) {
1987 if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1989 qreal bias = averageSize / 2 + 1 - (pressed ? data.pressPos : 0);
1990 if (isContentFlowReversed())
1993 -snapPosAt(-(dataValue - highlightRangeStart) + bias) + highlightRangeStart;
1994 maxDistance = qAbs(data.flickTarget - data.move.value());
1995 velocity = -maxVelocity;
1997 maxDistance = qAbs(maxExtent - data.move.value());
2000 if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
2001 data.flickTarget = maxExtent;
2003 bool overShoot = boundsBehavior & QQuickFlickable::OvershootBounds;
2004 if (maxDistance > 0 || overShoot) {
2010 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
2016 if (!hData.flicking && !vData.flicking) {
2018 qreal accel = eventType == QEvent::Wheel ? wheelDeceleration : deceleration;
2020 overshootDist = 0.0;
2022 qreal dist = v2 / (accel * 2.0) + averageSize/4;
2023 if (maxDistance > 0)
2024 dist = qMin(dist, maxDistance);
2027 if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickListView::SnapOneItem) {
2028 if (snapMode != QQuickListView::SnapOneItem) {
2029 qreal distTemp = isContentFlowReversed() ? -dist : dist;
2030 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + distTemp) + highlightRangeStart;
2034 if (data.flickTarget > minExtent) {
2035 overshootDist = overShootDistance(vSize);
2036 data.flickTarget += overshootDist;
2037 }
else if (data.flickTarget < maxExtent) {
2038 overshootDist = overShootDistance(vSize);
2039 data.flickTarget -= overshootDist;
2042 qreal adjDist = -data.flickTarget + data.move.value();
2043 if (qAbs(adjDist) > qAbs(dist)) {
2045 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
2054 accel = v2 / (2.0f * qAbs(dist));
2055 }
else if (overShoot) {
2056 data.flickTarget = data.move.value() - dist;
2057 if (data.flickTarget > minExtent) {
2058 overshootDist = overShootDistance(vSize);
2059 data.flickTarget += overshootDist;
2060 }
else if (data.flickTarget < maxExtent) {
2061 overshootDist = overShootDistance(vSize);
2062 data.flickTarget -= overshootDist;
2065 timeline.reset(data.move);
2066 timeline.accel(data.move, v, accel, maxDistance + overshootDist);
2067 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback,
this));
2072 qreal newtarget = data.flickTarget;
2073 if (snapMode != QQuickListView::NoSnap || highlightRange == QQuickListView::StrictlyEnforceRange) {
2074 qreal tempFlickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget;
2075 newtarget = -snapPosAt(-(tempFlickTarget - highlightRangeStart)) + highlightRangeStart;
2076 newtarget = isContentFlowReversed() ? -newtarget+size() : newtarget;
2078 if (velocity < 0 && newtarget <= maxExtent)
2079 newtarget = maxExtent - overshootDist;
2080 else if (velocity > 0 && newtarget >= minExtent)
2081 newtarget = minExtent + overshootDist;
2082 if (newtarget == data.flickTarget) {
2083 if (qAbs(velocity) < _q_MinimumFlickVelocity)
2087 data.flickTarget = newtarget;
2088 qreal dist = -newtarget + data.move.value();
2089 if ((v < 0 && dist < 0) || (v > 0 && dist > 0)) {
2091 timeline.reset(data.move);
2092 fixup(data, minExtent, maxExtent);
2095 timeline.reset(data.move);
2096 timeline.accelDistance(data.move, v, -dist);
2097 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback,
this));
2102 timeline.reset(data.move);
2103 fixup(data, minExtent, maxExtent);
3582void QQuickListView::viewportMoved(Qt::Orientations orient)
3584 Q_D(QQuickListView);
3585 QQuickItemView::viewportMoved(orient);
3587 if (!d->itemCount) {
3588 if (d->hasStickyHeader())
3590 if (d->hasStickyFooter())
3596 if (d->inViewportMoved)
3598 d->inViewportMoved =
true;
3601 if (d->isBottomToTop())
3602 d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
3604 d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
3606 if (d->isRightToLeft())
3607 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
3609 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
3612 d->refillOrLayout();
3615 qreal from = d->isContentFlowReversed() ? -d->position()-d->displayMarginBeginning-d->size() : d->position()-d->displayMarginBeginning;
3616 qreal to = d->isContentFlowReversed() ? -d->position()+d->displayMarginEnd : d->position()+d->size()+d->displayMarginEnd;
3617 for (FxViewItem *item : std::as_const(d->visibleItems)) {
3619 QQuickItemPrivate::get(item->item)->setCulled(item->endPosition() < from || item->position() > to);
3622 QQuickItemPrivate::get(d->currentItem->item)->setCulled(d->currentItem->endPosition() < from || d->currentItem->position() > to);
3624 if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
3625 d->moveReason = QQuickListViewPrivate::Mouse;
3626 if (d->moveReason != QQuickListViewPrivate::SetIndex) {
3627 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
3629 qreal pos = d->highlight->position();
3630 qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
3631 if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
3632 pos = viewPos + d->highlightRangeEnd - d->highlight->size();
3633 if (pos < viewPos + d->highlightRangeStart)
3634 pos = viewPos + d->highlightRangeStart;
3635 if (pos != d->highlight->position()) {
3636 d->highlightPosAnimator->stop();
3637 static_cast<FxListItemSG*>(d->highlight.get())->setPosition(pos);
3639 d->updateHighlight();
3643 if (FxViewItem *snapItem = d->snapItemAt(d->highlight->position())) {
3644 if (snapItem->index >= 0 && snapItem->index != d->currentIndex)
3645 d->updateCurrent(snapItem->index);
3650 if ((d->hData.flicking || d->vData.flicking) && d->correctFlick && !d->inFlickCorrection) {
3651 d->inFlickCorrection =
true;
3654 if (yflick() && !d->vData.inOvershoot) {
3655 if (d->vData.velocity > 0) {
3656 const qreal minY = minYExtent();
3657 if ((minY - d->vData.move.value() < height()/2 || d->vData.flickTarget - d->vData.move.value() < height()/2)
3658 && minY != d->vData.flickTarget)
3659 d->flickY(QEvent::TouchUpdate, -d->vData.smoothVelocity.value());
3660 }
else if (d->vData.velocity < 0) {
3661 const qreal maxY = maxYExtent();
3662 if ((d->vData.move.value() - maxY < height()/2 || d->vData.move.value() - d->vData.flickTarget < height()/2)
3663 && maxY != d->vData.flickTarget)
3664 d->flickY(QEvent::TouchUpdate, -d->vData.smoothVelocity.value());
3668 if (xflick() && !d->hData.inOvershoot) {
3669 if (d->hData.velocity > 0) {
3670 const qreal minX = minXExtent();
3671 if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2)
3672 && minX != d->hData.flickTarget)
3673 d->flickX(QEvent::TouchUpdate, -d->hData.smoothVelocity.value());
3674 }
else if (d->hData.velocity < 0) {
3675 const qreal maxX = maxXExtent();
3676 if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2)
3677 && maxX != d->hData.flickTarget)
3678 d->flickX(QEvent::TouchUpdate, -d->hData.smoothVelocity.value());
3681 d->inFlickCorrection =
false;
3683 if (d->hasStickyHeader())
3685 if (d->hasStickyFooter())
3687 if (d->sectionCriteria) {
3688 d->updateCurrentSection();
3689 d->updateStickySections();
3691 d->inViewportMoved =
false;
3858 Q_Q(QQuickListView);
3859#if !QT_CONFIG(quick_viewtransitions)
3860 Q_UNUSED(movingIntoView)
3862 int modelIndex = change.index;
3863 int count = change.count;
3865 if (q->size().isNull() && visibleItems.isEmpty())
3868 qreal tempPos = isContentFlowReversed() ? -position()-size() : position();
3869 int index = visibleItems.size() ? mapFromModel(modelIndex) : 0;
3870 qreal lastVisiblePos = buffer + displayMarginEnd + tempPos + size();
3873 int i = visibleItems.size() - 1;
3874 while (i > 0 && visibleItems.at(i)->index == -1)
3876 if (i == 0 && visibleItems.constFirst()->index == -1) {
3878 index = visibleItems.size();
3879 }
else if (visibleItems.at(i)->index + 1 == modelIndex
3880 && visibleItems.at(i)->endPosition() <= lastVisiblePos) {
3882 index = visibleItems.size();
3884 if (modelIndex < visibleIndex) {
3886 visibleIndex += count;
3887 for (FxViewItem *item : std::as_const(visibleItems)) {
3888 if (item->index != -1 && item->index >= modelIndex)
3889 item->index += count;
3898 if (visibleItems.size()) {
3899 pos = index < visibleItems.size() ? visibleItems.at(index)->position()
3900 : visibleItems.constLast()->endPosition() + spacing;
3904 for (FxViewItem *item : std::as_const(visibleItems)) {
3905 if (item->index != -1 && item->index >= modelIndex) {
3906 item->index += count;
3907#if QT_CONFIG(quick_viewtransitions)
3908 if (change.isMove())
3909 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition,
false);
3911 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition,
false);
3916 bool visibleAffected =
false;
3917 if (insertResult->visiblePos.isValid() && pos < insertResult->visiblePos) {
3919 int insertionIdx = index;
3920 qreal from = tempPos - displayMarginBeginning - buffer;
3922 if (insertionIdx < visibleIndex) {
3925 insertResult->sizeChangesBeforeVisiblePos += count * (averageSize + spacing);
3929 for (; it.hasNext() && pos >= from; it
.next()) {
3931 FxViewItem *item =
nullptr;
3932 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(it.index))))
3933 item->index = it.index;
3935 item = createItem(it.index, QQmlIncubator::Synchronous);
3941 visibleAffected =
true;
3942 visibleItems.insert(insertionIdx, item);
3943 if (insertionIdx == 0)
3944 insertResult->changedFirstItem =
true;
3945 if (!change.isMove()) {
3946 addedItems->append(item);
3947#if QT_CONFIG(quick_viewtransitions)
3949 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition,
true);
3952 static_cast<FxListItemSG *>(item)->setPosition(pos,
true);
3954 insertResult->sizeChangesBeforeVisiblePos += item->size() + spacing;
3955 pos -= item->size() + spacing;
3960 int firstOkIdx = -1;
3961 for (
int i = 0; i <= insertionIdx && i < visibleItems.size() - 1; i++) {
3962 if (visibleItems.at(i)->index + 1 != visibleItems.at(i + 1)->index) {
3967 for (
int i = 0; i < firstOkIdx; i++) {
3968 FxViewItem *nvItem = visibleItems.takeFirst();
3969 addedItems->removeOne(nvItem);
3975 for (; it.hasNext() && pos <= lastVisiblePos; it
.next()) {
3976 visibleAffected =
true;
3977 FxViewItem *item =
nullptr;
3978 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(it.index))))
3979 item->index = it.index;
3980#if QT_CONFIG(quick_viewtransitions)
3981 bool newItem = !item;
3985 item = createItem(it.index, QQmlIncubator::Synchronous);
3989 releaseItem(item, reusableFlag);
3993 if (index < visibleItems.size())
3994 visibleItems.insert(index, item);
3996 visibleItems.append(item);
3998 insertResult->changedFirstItem =
true;
3999 if (change.isMove()) {
4002#if QT_CONFIG(quick_viewtransitions)
4003 if (newItem && transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition,
true))
4004 movingIntoView->append(MovedItem(item, change.moveKey(item->index)));
4007 addedItems->append(item);
4008#if QT_CONFIG(quick_viewtransitions)
4010 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition,
true);
4013 static_cast<FxListItemSG *>(item)->setPosition(pos,
true);
4015 insertResult->sizeChangesAfterVisiblePos += item->size() + spacing;
4016 pos += item->size() + spacing;
4021 if (0 < index && index < visibleItems.size()) {
4022 FxViewItem *prevItem = visibleItems.at(index - 1);
4023 FxViewItem *item = visibleItems.at(index);
4024 if (prevItem->index != item->index - 1) {
4026#if QT_CONFIG(quick_viewtransitions)
4027 qreal prevPos = prevItem->position();
4029 while (i < visibleItems.size()) {
4030 FxListItemSG *nvItem =
static_cast<FxListItemSG *>(visibleItems.takeLast());
4031 insertResult->sizeChangesAfterVisiblePos -= nvItem->size() + spacing;
4032 addedItems->removeOne(nvItem);
4033#if QT_CONFIG(quick_viewtransitions)
4034 if (nvItem->transitionScheduledOrRunning())
4035 nvItem->setPosition(prevPos + (nvItem->index - prevItem->index) * averageSize);
4043 updateVisibleIndex();
4045 return visibleAffected;