739 qreal itemEnd = visiblePos;
740 if (visibleItems.size()) {
741 visiblePos = (*visibleItems.constBegin())->position();
742 itemEnd = (*(visibleItems.constEnd() - 1))->endPosition() + spacing;
745 int modelIndex = findLastVisibleIndex();
746 bool haveValidItems = modelIndex >= 0;
747 modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
749 if (haveValidItems && (bufferFrom > itemEnd+averageSize+spacing
750 || bufferTo < visiblePos - averageSize - spacing)) {
753 int count = (fillFrom - itemEnd) / (averageSize + spacing);
754 int newModelIdx = qBound(0, modelIndex + count, model->count());
755 count = newModelIdx - modelIndex;
757 releaseVisibleItems(reusableFlag);
758 modelIndex = newModelIdx;
759 visibleIndex = modelIndex;
760 visiblePos = itemEnd + count * (averageSize + spacing);
761 itemEnd = visiblePos;
765 QQmlIncubator::IncubationMode incubationMode = doBuffer ? QQmlIncubator::Asynchronous : QQmlIncubator::AsynchronousIfNested;
767 bool changed =
false;
770 while (modelIndex < model->count() && pos <= fillTo) {
771 if (!(item =
static_cast<
FxListItemSG*>(createItem(modelIndex, incubationMode))))
773 qCDebug(lcItemViewDelegateLifecycle) <<
"refill: append item" << modelIndex <<
"pos" << pos <<
"buffer" << doBuffer <<
"item" << (QObject *)(item->item);
774#if QT_CONFIG(quick_viewtransitions)
775 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition,
true))
777 item->setPosition(pos,
true);
779 QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
780 pos += item->size() + spacing;
781 visibleItems.append(item);
786 if (doBuffer && requestedIndex != -1)
789 while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > fillFrom) {
790 if (!(item =
static_cast<
FxListItemSG*>(createItem(visibleIndex-1, incubationMode))))
792 qCDebug(lcItemViewDelegateLifecycle) <<
"refill: prepend item" << visibleIndex-1 <<
"current top pos" << visiblePos <<
"buffer" << doBuffer <<
"item" << (QObject *)(item->item);
794 visiblePos -= item->size() + spacing;
795#if QT_CONFIG(quick_viewtransitions)
796 if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition,
true))
798 item->setPosition(visiblePos,
true);
800 QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
801 visibleItems.prepend(item);
805 if (changed && sectionCriteria)
891 if (!visibleItems.isEmpty()) {
892 const qreal from = isContentFlowReversed() ? -position()-displayMarginBeginning-size() : position()-displayMarginBeginning;
893 const qreal to = isContentFlowReversed() ? -position()+displayMarginEnd : position()+size()+displayMarginEnd;
895 FxListItemSG *firstItem =
static_cast<FxListItemSG *>(visibleItems.constFirst());
896 bool fixedCurrent = currentItem && firstItem->item == currentItem->item;
898#if QT_CONFIG(quick_viewtransitions)
900
901 if (transitioner && transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition,
true))
902 resetFirstItemPosition(isContentFlowReversed() ? -firstItem->position()-firstItem->size() : firstItem->position());
905 firstVisibleItemPosition = firstItem->position();
906 qreal sum = firstItem->size();
907 qreal pos = firstItem->position() + firstItem->size() + spacing;
908 firstItem->setVisible(firstItem->endPosition() >= from && firstItem->position() <= to);
913 firstItem->setPosition(firstItem->position());
915 for (
int i=1; i < visibleItems.size(); ++i) {
916 FxListItemSG *item =
static_cast<FxListItemSG*>(visibleItems.at(i));
917 if (item->index >= fromModelIndex) {
918 item->setPosition(pos);
919 item->setVisible(item->endPosition() >= from && item->position() <= to);
921 pos += item->size() + spacing;
923 fixedCurrent = fixedCurrent || (currentItem && item->item == currentItem->item);
925 averageSize = qRound(sum / visibleItems.size());
928 if (currentIndex >= 0 && currentItem && !fixedCurrent)
929 static_cast<FxListItemSG*>(currentItem)->setPosition(positionAt(currentIndex));
986 bool changed =
false;
988 if (trackedItem == highlight.get())
989 trackedItem =
nullptr;
992 highlightPosAnimator.reset();
993 highlightWidthAnimator.reset();
994 highlightHeightAnimator.reset();
995 highlightPosAnimator =
nullptr;
996 highlightWidthAnimator =
nullptr;
997 highlightHeightAnimator =
nullptr;
1005 Q_Q(QQuickListView);
1007 QQuickItem *item = createHighlightItem();
1009 std::unique_ptr<FxListItemSG> newHighlight
1010 = std::make_unique<FxListItemSG>(item, q,
true);
1011 newHighlight->trackGeometry(
true);
1013 if (autoHighlight) {
1014 newHighlight->setSize(
static_cast<FxListItemSG*>(currentItem)->itemSize());
1015 newHighlight->setPosition(
static_cast<FxListItemSG*>(currentItem)->itemPosition());
1017 const QLatin1String posProp(orient == QQuickListView::Vertical ?
"y" :
"x");
1018 highlightPosAnimator = std::make_unique<QSmoothedAnimation>();
1019 highlightPosAnimator->target = QQmlProperty(item, posProp);
1020 highlightPosAnimator->velocity = highlightMoveVelocity;
1021 highlightPosAnimator->userDuration = highlightMoveDuration;
1023 highlightWidthAnimator = std::make_unique<QSmoothedAnimation>();
1024 highlightWidthAnimator->velocity = highlightResizeVelocity;
1025 highlightWidthAnimator->userDuration = highlightResizeDuration;
1026 highlightWidthAnimator->target = QQmlProperty(item, QStringLiteral(
"width"));
1028 highlightHeightAnimator = std::make_unique<QSmoothedAnimation>();
1029 highlightHeightAnimator->velocity = highlightResizeVelocity;
1030 highlightHeightAnimator->userDuration = highlightResizeDuration;
1031 highlightHeightAnimator->target = QQmlProperty(item, QStringLiteral(
"height"));
1033 highlight = std::move(newHighlight);
1038 emit q->highlightItemChanged();
1092 Q_Q(QQuickListView);
1093 QQuickItem *sectionItem =
nullptr;
1100 sectionItem->setVisible(
true);
1101 QQmlContext *context = QQmlEngine::contextForObject(sectionItem)->parentContext();
1102 setSectionHelper(context, sectionItem, section);
1104 QQmlComponent* delegate = sectionCriteria->delegate();
1105 const bool reuseExistingContext = delegate->isBound();
1106 auto delegatePriv = QQmlComponentPrivate::get(delegate);
1107 QQmlPropertyCache::ConstPtr rootPropertyCache;
1109 QQmlContext *creationContext = sectionCriteria->delegate()->creationContext();
1110 auto baseContext = creationContext ? creationContext : qmlContext(q);
1112 QQmlContext *context = reuseExistingContext ? baseContext :
new QQmlContext(baseContext);
1113 QObject *nobj = delegate->beginCreate(context);
1115 if (delegatePriv->hadTopLevelRequiredProperties()) {
1116 delegate->setInitialProperties(nobj, {{QLatin1String(
"section"), section}});
1117 }
else if (!reuseExistingContext) {
1118 context->setContextProperty(QLatin1String(
"section"), section);
1120 if (!reuseExistingContext)
1121 QQml_setParent_noEvent(context, nobj);
1122 sectionItem = qobject_cast<QQuickItem *>(nobj);
1126 if (qFuzzyIsNull(sectionItem->z()))
1127 sectionItem->setZ(2);
1128 QQml_setParent_noEvent(sectionItem, contentItem);
1129 sectionItem->setParentItem(contentItem);
1132 auto *attached =
static_cast<QQuickListViewAttached*>(qmlAttachedPropertiesObject<QQuickListView>(sectionItem));
1133 attached->setView(q);
1134 }
else if (!reuseExistingContext) {
1137 sectionCriteria->delegate()->completeCreate();
1141 QQuickItemPrivate::get(sectionItem)->addItemChangeListener(
this, QQuickItemPrivate::Geometry);
1251 if (!sectionCriteria || !sectionCriteria->delegate()
1252 || (!sectionCriteria->labelPositioning() && !currentSectionItem && !nextSectionItem))
1256 qreal viewPos = isFlowReversed ? -position()-size() : position();
1257 qreal startPos = hasStickyHeader() ? header->endPosition() : viewPos;
1258 qreal endPos = hasStickyFooter() ? footer->position() : viewPos + size();
1260 QQuickItem *sectionItem =
nullptr;
1261 QQuickItem *lastSectionItem =
nullptr;
1263 while (index < visibleItems.size()) {
1264 if (QQuickItem *section =
static_cast<FxListItemSG *>(visibleItems.at(index))->section()) {
1267 qreal sectionPos = orient == QQuickListView::Vertical ? section->y() : section->x();
1268 qreal sectionSize = orient == QQuickListView::Vertical ? section->height() : section->width();
1270 if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
1271 visTop = isFlowReversed ? -sectionPos-sectionSize >= startPos : sectionPos >= startPos;
1273 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd)
1274 visBot = isFlowReversed ? -sectionPos <= endPos : sectionPos + sectionSize < endPos;
1275 section->setVisible(visBot && visTop);
1276 if (visTop && !sectionItem)
1277 sectionItem = section;
1278 if (isFlowReversed) {
1279 if (-sectionPos <= endPos)
1280 lastSectionItem = section;
1282 if (sectionPos + sectionSize < endPos)
1283 lastSectionItem = section;
1290 if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart && isValid() && visibleItems.size()) {
1292 currentSectionItem = getSectionItem(currentSection);
1293 }
else if (QString::compare(currentStickySection, currentSection, Qt::CaseInsensitive)) {
1294 QQmlContext *context = QQmlEngine::contextForObject(currentSectionItem)->parentContext();
1297 currentStickySection = currentSection;
1301 qreal sectionSize = orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
1302 bool atBeginning = orient == QQuickListView::Vertical ? (isBottomToTop() ? vData.atEnd : vData.atBeginning) : (isRightToLeft() ? hData.atEnd : hData.atBeginning);
1304 currentSectionItem->setVisible(!atBeginning && (!header || hasStickyHeader() || header->endPosition() < viewPos));
1305 qreal pos = isFlowReversed ? position() + size() - sectionSize : startPos;
1307 pos = isFlowReversed ? qMin(-header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
1309 qreal sectionPos = orient == QQuickListView::Vertical ? sectionItem->y() : sectionItem->x();
1310 pos = isFlowReversed ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize);
1313 pos = isFlowReversed ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
1314 if (orient == QQuickListView::Vertical)
1324 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd && isValid() && visibleItems.size()) {
1326 nextSectionItem = getSectionItem(nextSection);
1327 }
else if (QString::compare(nextStickySection, nextSection, Qt::CaseInsensitive)) {
1328 QQmlContext *context = QQmlEngine::contextForObject(nextSectionItem)->parentContext();
1331 nextStickySection = nextSection;
1335 qreal sectionSize = orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1337 qreal pos = isFlowReversed ? position() : endPos - sectionSize;
1339 pos = isFlowReversed ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
1340 if (lastSectionItem) {
1341 qreal sectionPos = orient == QQuickListView::Vertical ? lastSectionItem->y() : lastSectionItem->x();
1342 pos = isFlowReversed ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize);
1345 pos = isFlowReversed ? qMin(-header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
1346 if (orient == QQuickListView::Vertical)
1400 Q_Q(QQuickListView);
1401 if (!sectionCriteria || visibleItems.isEmpty()) {
1402 if (!currentSection.isEmpty()) {
1403 currentSection.clear();
1404 emit q->currentSectionChanged();
1408 bool inlineSections = sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels;
1409 qreal viewPos = isContentFlowReversed() ? -position()-size() : position();
1410 qreal startPos = hasStickyHeader() ? header->endPosition() : viewPos;
1412 int modelIndex = visibleIndex;
1413 while (index < visibleItems.size()) {
1414 FxViewItem *item = visibleItems.at(index);
1415 if (item->endPosition() > startPos)
1417 if (item->index != -1)
1418 modelIndex = item->index;
1422 QString newSection = currentSection;
1423 if (index < visibleItems.size())
1424 newSection = visibleItems.at(index)->attached->section();
1426 newSection = (*visibleItems.constBegin())->attached->section();
1427 if (newSection != currentSection) {
1428 currentSection = newSection;
1430 emit q->currentSectionChanged();
1433 if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd) {
1438 QString lastSection = currentSection;
1439 qreal endPos = hasStickyFooter() ? footer->position() : viewPos + size();
1440 if (nextSectionItem && !inlineSections)
1441 endPos -= orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
1442 while (index < visibleItems.size()) {
1443 FxListItemSG *listItem =
static_cast<FxListItemSG *>(visibleItems.at(index));
1444 if (listItem->itemPosition() >= endPos)
1446 if (listItem->index != -1)
1447 modelIndex = listItem->index;
1448 lastSection = listItem->attached->section();
1452 if (lastVisibleSection != lastSection) {
1453 nextSection = QString();
1454 lastVisibleSection = lastSection;
1455 for (
int i = modelIndex; i < itemCount; ++i) {
1456 QString section = sectionAt(i);
1457 if (section != lastSection) {
1458 nextSection = section;
1590 Q_Q(QQuickListView);
1591 bool created =
false;
1593 QQuickItem *item = createComponentItem(headerComponent, 1.0);
1596 header =
new FxListItemSG(item, q,
true);
1597 header->trackGeometry(
true);
1601 FxListItemSG *listItem =
static_cast<FxListItemSG*>(header);
1602 if (headerPositioning == QQuickListView::OverlayHeader) {
1604 }
else if (visibleItems.size()) {
1605 const bool fixingUp = (orient == QQuickListView::Vertical ? vData : hData).fixingUp;
1606 if (headerPositioning == QQuickListView::PullBackHeader) {
1607 qreal headerPosition = listItem->position();
1610 if (fixingUp && !headerNeedsSeparateFixup)
1611 headerPosition = viewPos - headerSize();
1614 qreal clampedPos = qMax(originPosition() - headerSize(), qMin(headerPosition, lastPosition() - size()));
1615 listItem->setPosition(qBound(viewPos - headerSize(), clampedPos, viewPos),
false,
false);
1617 qreal startPos = originPosition();
1618 if (visibleIndex == 0) {
1619 listItem->setPosition(startPos - headerSize(),
false,
false);
1621 if (position() <= startPos || listItem->position() > startPos - headerSize())
1622 listItem->setPosition(startPos - headerSize(),
false,
false);
1626 listItem->setPosition(-headerSize(),
false,
false);
1630 emit q->headerItemChanged();
1652 const QRectF &oldGeometry)
1654 Q_Q(QQuickListView);
1656 QQuickItemViewPrivate::itemGeometryChanged(item, change, oldGeometry);
1657 if (!q->isComponentComplete())
1660 if (currentItem && currentItem->item == item) {
1662 const qreal pos = position();
1663 const qreal sz = size();
1664 const qreal from = contentFlowReversed ? -pos - displayMarginBeginning - sz : pos - displayMarginBeginning;
1665 const qreal to = contentFlowReversed ? -pos + displayMarginEnd : pos + sz + displayMarginEnd;
1666 QQuickItemPrivate::get(currentItem->item)->setCulled(currentItem->endPosition() < from || currentItem->position() > to);
1669 if (item != contentItem && (!highlight || item != highlight->item)) {
1670 if ((orient == QQuickListView::Vertical && change.heightChange())
1671 || (orient == QQuickListView::Horizontal && change.widthChange())) {
1675 if (visibleItems.size() && item == visibleItems.constFirst()->item) {
1676 FxListItemSG *listItem =
static_cast<FxListItemSG*>(visibleItems.constFirst());
1677#if QT_CONFIG(quick_viewtransitions)
1678 if (listItem->transitionScheduledOrRunning())
1681 if (orient == QQuickListView::Vertical) {
1682 const qreal oldItemEndPosition = verticalLayoutDirection == QQuickItemView::BottomToTop ? -oldGeometry.y() : oldGeometry.y() + oldGeometry.height();
1683 const qreal heightDiff = item->height() - oldGeometry.height();
1684 if (verticalLayoutDirection == QQuickListView::TopToBottom && oldItemEndPosition < q->contentY())
1685 listItem->setPosition(listItem->position() - heightDiff,
true);
1686 else if (verticalLayoutDirection == QQuickListView::BottomToTop && oldItemEndPosition > q->contentY())
1687 listItem->setPosition(listItem->position() + heightDiff,
true);
1689 const qreal oldItemEndPosition = q->effectiveLayoutDirection() == Qt::RightToLeft ? -oldGeometry.x() : oldGeometry.x() + oldGeometry.width();
1690 const qreal widthDiff = item->width() - oldGeometry.width();
1691 if (q->effectiveLayoutDirection() == Qt::LeftToRight && oldItemEndPosition < q->contentX())
1692 listItem->setPosition(listItem->position() - widthDiff,
true);
1693 else if (q->effectiveLayoutDirection() == Qt::RightToLeft && oldItemEndPosition > q->contentX())
1694 listItem->setPosition(listItem->position() + widthDiff,
true);
1697 forceLayoutPolish();
1713 if (orient == QQuickListView::Horizontal && &data == &vData) {
1714 if (flickableDirection != QQuickFlickable::HorizontalFlick)
1715 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1717 }
else if (orient == QQuickListView::Vertical && &data == &hData) {
1718 if (flickableDirection != QQuickFlickable::VerticalFlick)
1719 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1724 if (visibleItems.size() == 0)
1728 fixupMode = moveReason == Mouse ? fixupMode : Immediate;
1729 bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
1731 qreal viewPos = isContentFlowReversed() ? -position()-size() : position();
1733 if (snapMode != QQuickListView::NoSnap && moveReason != QQuickListViewPrivate::SetIndex) {
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750 qreal tempPosition = isContentFlowReversed() ? -position()-size() : position();
1751 if (snapMode == QQuickListView::SnapOneItem && moveReason == Mouse) {
1753 qreal dist = data.move.value() - data.pressPos;
1756 bias = averageSize/2;
1758 bias = -averageSize/2;
1759 if (isContentFlowReversed())
1761 tempPosition -= bias;
1764 qreal snapOffset = 0;
1765 qreal overlayHeaderOffset = 0;
1766 bool isHeaderWithinBounds =
false;
1768 qreal visiblePartOfHeader = header->position() + header->size() - tempPosition;
1769 isHeaderWithinBounds = visiblePartOfHeader > 0;
1770 switch (headerPositioning) {
1771 case QQuickListView::OverlayHeader:
1772 snapOffset = header->size();
1773 overlayHeaderOffset = header->size();
1775 case QQuickListView::InlineHeader:
1776 if (isHeaderWithinBounds && tempPosition < originPosition())
1780 snapOffset = header->size() / 2;
1782 case QQuickListView::PullBackHeader:
1783 desiredHeaderVisible = visiblePartOfHeader > header->size()/2;
1784 if (qFuzzyCompare(header->position(), tempPosition)) {
1786 snapOffset = header->size();
1790 snapOffset = header->size();
1791 overlayHeaderOffset = header->size();
1800 if (strictHighlightRange)
1803 FxViewItem *topItem =
nullptr;
1804 FxViewItem *bottomItem =
nullptr;
1806 topItem = visibleItem(snapResizeTargetIndex);
1807 bottomItem = topItem;
1810 topItem = snapItemAt(tempPosition + snapOffset + highlightRangeStart);
1812 bottomItem = snapItemAt(tempPosition + snapOffset + highlightRangeEnd);
1813 if (strictHighlightRange && currentItem) {
1815 if (!topItem || (topItem->index != currentIndex && fixupMode == Immediate))
1816 topItem = currentItem;
1817 if (!bottomItem || (bottomItem->index != currentIndex && fixupMode == Immediate))
1818 bottomItem = currentItem;
1822 bool isInBounds = -position() > maxExtent && -position() <= minExtent;
1824 if (header && !topItem && isInBounds) {
1826 switch (headerPositioning) {
1827 case QQuickListView::OverlayHeader:
1828 pos = startPosition() - overlayHeaderOffset;
1830 case QQuickListView::InlineHeader:
1831 pos = isContentFlowReversed() ? header->size() - size() : header->position();
1833 case QQuickListView::PullBackHeader:
1834 pos = isContentFlowReversed() ? -size() : startPosition();
1837 }
else if (topItem && (isInBounds || strictHighlightRange)) {
1838 if (topItem->index == 0 && header && !hasStickyHeader() && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) {
1839 pos = isContentFlowReversed() ? -header->position() + highlightRangeStart - size() : (header->position() - highlightRangeStart + header->size());
1841 if (header && headerPositioning == QQuickListView::PullBackHeader) {
1844 if (qFuzzyCompare(tempPosition, header->position())) {
1846 if (isContentFlowReversed())
1847 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + snapOffset;
1849 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - snapOffset;
1856 if (isContentFlowReversed())
1857 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + headerSize();
1859 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - headerSize();
1863 if (isContentFlowReversed())
1864 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size();
1866 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart;
1877 pos = qBound(-minExtent, pos, -maxExtent);
1878 desiredViewportPosition = isContentFlowReversed() ? -pos - size() : pos;
1880 FxListItemSG *headerItem =
static_cast<FxListItemSG*>(header);
1881 fixupHeaderPosition = headerItem->position();
1884 QObjectPrivate::connect(&timeline, &QQuickTimeLine::updated,
this, &QQuickListViewPrivate::fixupHeader);
1885 QObjectPrivate::connect(&timeline, &QQuickTimeLine::completed,
this, &QQuickListViewPrivate::fixupHeaderCompleted);
1888 pos = -
static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + overlayHeaderOffset;
1890 pos =
static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - overlayHeaderOffset;
1893 }
else if (bottomItem && isInBounds) {
1894 if (isContentFlowReversed())
1895 pos = -
static_cast<FxListItemSG*>(bottomItem)->itemPosition() + highlightRangeEnd - size() + overlayHeaderOffset;
1897 pos =
static_cast<FxListItemSG*>(bottomItem)->itemPosition() - highlightRangeEnd - overlayHeaderOffset;
1899 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1905 && (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
1906 && currentSectionItem) {
1907 auto sectionSize = (orient == QQuickListView::Vertical) ? currentSectionItem->height()
1908 : currentSectionItem->width();
1909 if (isContentFlowReversed())
1915 pos = qBound(-minExtent, pos, -maxExtent);
1917 qreal dist = qAbs(data.move + pos);
1922 timeline.reset(data.move);
1923 if (fixupMode != Immediate) {
1924 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1925 data.fixingUp =
true;
1927 timeline.set(data.move, -pos);
1929 vTime = timeline.time();
1931 }
else if (currentItem && strictHighlightRange && moveReason != QQuickListViewPrivate::SetIndex) {
1933 qreal pos =
static_cast<FxListItemSG*>(currentItem)->itemPosition();
1934 if (viewPos < pos +
static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd)
1935 viewPos = pos +
static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd;
1936 if (viewPos > pos - highlightRangeStart)
1937 viewPos = pos - highlightRangeStart;
1938 if (isContentFlowReversed())
1939 viewPos = -viewPos-size();
1941 timeline.reset(data.move);
1942 if (viewPos != position()) {
1943 if (fixupMode != Immediate) {
1944 if (fixupMode == ExtentChanged && data.fixingUp)
1945 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::OutQuad), fixupDuration/2);
1947 timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
1948 data.fixingUp =
true;
1950 timeline.set(data.move, -viewPos);
1953 vTime = timeline.time();
1955 QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
1957 data.inOvershoot =
false;
1962 QQuickTimeLineCallback::Callback fixupCallback, QEvent::Type eventType, qreal velocity)
1964 data.fixingUp =
false;
1966 if ((!haveHighlightRange || highlightRange != QQuickListView::StrictlyEnforceRange) && snapMode == QQuickListView::NoSnap) {
1968 return QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, eventType, velocity);
1970 qreal maxDistance = 0;
1971 const qreal dataValue =
1976 if (data.move.value() < minExtent) {
1977 if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1979 qreal bias = averageSize / 2 + 1 - (pressed ? data.pressPos : 0);
1980 if (isContentFlowReversed())
1982 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) - bias) + highlightRangeStart;
1983 maxDistance = qAbs(data.flickTarget - data.move.value());
1984 velocity = maxVelocity;
1986 maxDistance = qAbs(minExtent - data.move.value());
1989 if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
1990 data.flickTarget = minExtent;
1992 if (data.move.value() > maxExtent) {
1993 if (snapMode == QQuickListView::SnapOneItem && !hData.flicking && !vData.flicking) {
1995 qreal bias = averageSize / 2 + 1 - (pressed ? data.pressPos : 0);
1996 if (isContentFlowReversed())
1999 -snapPosAt(-(dataValue - highlightRangeStart) + bias) + highlightRangeStart;
2000 maxDistance = qAbs(data.flickTarget - data.move.value());
2001 velocity = -maxVelocity;
2003 maxDistance = qAbs(maxExtent - data.move.value());
2006 if (snapMode == QQuickListView::NoSnap && highlightRange != QQuickListView::StrictlyEnforceRange)
2007 data.flickTarget = maxExtent;
2009 bool overShoot = boundsBehavior & QQuickFlickable::OvershootBounds;
2010 if (maxDistance > 0 || overShoot) {
2016 if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
2022 if (!hData.flicking && !vData.flicking) {
2024 qreal accel = eventType == QEvent::Wheel ? wheelDeceleration : deceleration;
2026 overshootDist = 0.0;
2028 qreal dist = v2 / (accel * 2.0) + averageSize/4;
2029 if (maxDistance > 0)
2030 dist = qMin(dist, maxDistance);
2033 if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickListView::SnapOneItem) {
2034 if (snapMode != QQuickListView::SnapOneItem) {
2035 qreal distTemp = isContentFlowReversed() ? -dist : dist;
2036 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + distTemp) + highlightRangeStart;
2040 if (data.flickTarget > minExtent) {
2041 overshootDist = overShootDistance(vSize);
2042 data.flickTarget += overshootDist;
2043 }
else if (data.flickTarget < maxExtent) {
2044 overshootDist = overShootDistance(vSize);
2045 data.flickTarget -= overshootDist;
2048 qreal adjDist = -data.flickTarget + data.move.value();
2049 if (qAbs(adjDist) > qAbs(dist)) {
2051 qreal adjv2 = accel * 2.0f * qAbs(adjDist);
2060 accel = v2 / (2.0f * qAbs(dist));
2061 }
else if (overShoot) {
2062 data.flickTarget = data.move.value() - dist;
2063 if (data.flickTarget > minExtent) {
2064 overshootDist = overShootDistance(vSize);
2065 data.flickTarget += overshootDist;
2066 }
else if (data.flickTarget < maxExtent) {
2067 overshootDist = overShootDistance(vSize);
2068 data.flickTarget -= overshootDist;
2071 timeline.reset(data.move);
2072 timeline.accel(data.move, v, accel, maxDistance + overshootDist);
2073 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback,
this));
2078 qreal newtarget = data.flickTarget;
2079 if (snapMode != QQuickListView::NoSnap || highlightRange == QQuickListView::StrictlyEnforceRange) {
2080 qreal tempFlickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget;
2081 newtarget = -snapPosAt(-(tempFlickTarget - highlightRangeStart)) + highlightRangeStart;
2082 newtarget = isContentFlowReversed() ? -newtarget+size() : newtarget;
2084 if (velocity < 0 && newtarget <= maxExtent)
2085 newtarget = maxExtent - overshootDist;
2086 else if (velocity > 0 && newtarget >= minExtent)
2087 newtarget = minExtent + overshootDist;
2088 if (newtarget == data.flickTarget) {
2089 if (qAbs(velocity) < _q_MinimumFlickVelocity)
2093 data.flickTarget = newtarget;
2094 qreal dist = -newtarget + data.move.value();
2095 if ((v < 0 && dist < 0) || (v > 0 && dist > 0)) {
2097 timeline.reset(data.move);
2098 fixup(data, minExtent, maxExtent);
2101 timeline.reset(data.move);
2102 timeline.accelDistance(data.move, v, -dist);
2103 timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback,
this));
2108 timeline.reset(data.move);
2109 fixup(data, minExtent, maxExtent);
3588void QQuickListView::viewportMoved(Qt::Orientations orient)
3590 Q_D(QQuickListView);
3591 QQuickItemView::viewportMoved(orient);
3593 if (!d->itemCount) {
3594 if (d->hasStickyHeader())
3596 if (d->hasStickyFooter())
3602 if (d->inViewportMoved)
3604 d->inViewportMoved =
true;
3607 if (d->isBottomToTop())
3608 d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
3610 d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
3612 if (d->isRightToLeft())
3613 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
3615 d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
3618 d->refillOrLayout();
3621 qreal from = d->isContentFlowReversed() ? -d->position()-d->displayMarginBeginning-d->size() : d->position()-d->displayMarginBeginning;
3622 qreal to = d->isContentFlowReversed() ? -d->position()+d->displayMarginEnd : d->position()+d->size()+d->displayMarginEnd;
3623 for (FxViewItem *item : std::as_const(d->visibleItems)) {
3625 QQuickItemPrivate::get(item->item)->setCulled(item->endPosition() < from || item->position() > to);
3628 QQuickItemPrivate::get(d->currentItem->item)->setCulled(d->currentItem->endPosition() < from || d->currentItem->position() > to);
3630 if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
3631 d->moveReason = QQuickListViewPrivate::Mouse;
3632 if (d->moveReason != QQuickListViewPrivate::SetIndex) {
3633 if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
3635 qreal pos = d->highlight->position();
3636 qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
3637 if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
3638 pos = viewPos + d->highlightRangeEnd - d->highlight->size();
3639 if (pos < viewPos + d->highlightRangeStart)
3640 pos = viewPos + d->highlightRangeStart;
3641 if (pos != d->highlight->position()) {
3642 d->highlightPosAnimator->stop();
3643 static_cast<FxListItemSG*>(d->highlight.get())->setPosition(pos);
3645 d->updateHighlight();
3649 if (FxViewItem *snapItem = d->snapItemAt(d->highlight->position())) {
3650 if (snapItem->index >= 0 && snapItem->index != d->currentIndex)
3651 d->updateCurrent(snapItem->index);
3656 if ((d->hData.flicking || d->vData.flicking) && d->correctFlick && !d->inFlickCorrection) {
3657 d->inFlickCorrection =
true;
3660 if (yflick() && !d->vData.inOvershoot) {
3661 if (d->vData.velocity > 0) {
3662 const qreal minY = minYExtent();
3663 if ((minY - d->vData.move.value() < height()/2 || d->vData.flickTarget - d->vData.move.value() < height()/2)
3664 && minY != d->vData.flickTarget)
3665 d->flickY(QEvent::TouchUpdate, -d->vData.smoothVelocity.value());
3666 }
else if (d->vData.velocity < 0) {
3667 const qreal maxY = maxYExtent();
3668 if ((d->vData.move.value() - maxY < height()/2 || d->vData.move.value() - d->vData.flickTarget < height()/2)
3669 && maxY != d->vData.flickTarget)
3670 d->flickY(QEvent::TouchUpdate, -d->vData.smoothVelocity.value());
3674 if (xflick() && !d->hData.inOvershoot) {
3675 if (d->hData.velocity > 0) {
3676 const qreal minX = minXExtent();
3677 if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2)
3678 && minX != d->hData.flickTarget)
3679 d->flickX(QEvent::TouchUpdate, -d->hData.smoothVelocity.value());
3680 }
else if (d->hData.velocity < 0) {
3681 const qreal maxX = maxXExtent();
3682 if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2)
3683 && maxX != d->hData.flickTarget)
3684 d->flickX(QEvent::TouchUpdate, -d->hData.smoothVelocity.value());
3687 d->inFlickCorrection =
false;
3689 if (d->hasStickyHeader())
3691 if (d->hasStickyFooter())
3693 if (d->sectionCriteria) {
3694 d->updateCurrentSection();
3695 d->updateStickySections();
3697 d->inViewportMoved =
false;
3864 Q_Q(QQuickListView);
3865#if !QT_CONFIG(quick_viewtransitions)
3866 Q_UNUSED(movingIntoView)
3868 int modelIndex = change.index;
3869 int count = change.count;
3871 if (q->size().isNull() && visibleItems.isEmpty())
3874 qreal tempPos = isContentFlowReversed() ? -position()-size() : position();
3875 int index = visibleItems.size() ? mapFromModel(modelIndex) : 0;
3876 qreal lastVisiblePos = buffer + displayMarginEnd + tempPos + size();
3879 int i = visibleItems.size() - 1;
3880 while (i > 0 && visibleItems.at(i)->index == -1)
3882 if (i == 0 && visibleItems.constFirst()->index == -1) {
3884 index = visibleItems.size();
3885 }
else if (visibleItems.at(i)->index + 1 == modelIndex
3886 && visibleItems.at(i)->endPosition() <= lastVisiblePos) {
3888 index = visibleItems.size();
3890 if (modelIndex < visibleIndex) {
3892 visibleIndex += count;
3893 for (FxViewItem *item : std::as_const(visibleItems)) {
3894 if (item->index != -1 && item->index >= modelIndex)
3895 item->index += count;
3904 if (visibleItems.size()) {
3905 pos = index < visibleItems.size() ? visibleItems.at(index)->position()
3906 : visibleItems.constLast()->endPosition() + spacing;
3910 for (FxViewItem *item : std::as_const(visibleItems)) {
3911 if (item->index != -1 && item->index >= modelIndex) {
3912 item->index += count;
3913#if QT_CONFIG(quick_viewtransitions)
3914 if (change.isMove())
3915 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition,
false);
3917 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition,
false);
3922 bool visibleAffected =
false;
3923 if (insertResult->visiblePos.isValid() && pos < insertResult->visiblePos) {
3925 int insertionIdx = index;
3926 qreal from = tempPos - displayMarginBeginning - buffer;
3928 if (insertionIdx < visibleIndex) {
3931 insertResult->sizeChangesBeforeVisiblePos += count * (averageSize + spacing);
3935 for (; it.hasNext() && pos >= from; it
.next()) {
3937 FxViewItem *item =
nullptr;
3938 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(it.index))))
3939 item->index = it.index;
3941 item = createItem(it.index, QQmlIncubator::Synchronous);
3947 visibleAffected =
true;
3948 visibleItems.insert(insertionIdx, item);
3949 if (insertionIdx == 0)
3950 insertResult->changedFirstItem =
true;
3951 if (!change.isMove()) {
3952 addedItems->append(item);
3953#if QT_CONFIG(quick_viewtransitions)
3955 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition,
true);
3958 static_cast<FxListItemSG *>(item)->setPosition(pos,
true);
3960 insertResult->sizeChangesBeforeVisiblePos += item->size() + spacing;
3961 pos -= item->size() + spacing;
3966 int firstOkIdx = -1;
3967 for (
int i = 0; i <= insertionIdx && i < visibleItems.size() - 1; i++) {
3968 if (visibleItems.at(i)->index + 1 != visibleItems.at(i + 1)->index) {
3973 for (
int i = 0; i < firstOkIdx; i++) {
3974 FxViewItem *nvItem = visibleItems.takeFirst();
3975 addedItems->removeOne(nvItem);
3981 for (; it.hasNext() && pos <= lastVisiblePos; it
.next()) {
3982 visibleAffected =
true;
3983 FxViewItem *item =
nullptr;
3984 if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(it.index))))
3985 item->index = it.index;
3986#if QT_CONFIG(quick_viewtransitions)
3987 bool newItem = !item;
3991 item = createItem(it.index, QQmlIncubator::Synchronous);
3995 releaseItem(item, reusableFlag);
3999 if (index < visibleItems.size())
4000 visibleItems.insert(index, item);
4002 visibleItems.append(item);
4004 insertResult->changedFirstItem =
true;
4005 if (change.isMove()) {
4008#if QT_CONFIG(quick_viewtransitions)
4009 if (newItem && transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition,
true))
4010 movingIntoView->append(MovedItem(item, change.moveKey(item->index)));
4013 addedItems->append(item);
4014#if QT_CONFIG(quick_viewtransitions)
4016 item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition,
true);
4019 static_cast<FxListItemSG *>(item)->setPosition(pos,
true);
4021 insertResult->sizeChangesAfterVisiblePos += item->size() + spacing;
4022 pos += item->size() + spacing;
4027 if (0 < index && index < visibleItems.size()) {
4028 FxViewItem *prevItem = visibleItems.at(index - 1);
4029 FxViewItem *item = visibleItems.at(index);
4030 if (prevItem->index != item->index - 1) {
4032#if QT_CONFIG(quick_viewtransitions)
4033 qreal prevPos = prevItem->position();
4035 while (i < visibleItems.size()) {
4036 FxListItemSG *nvItem =
static_cast<FxListItemSG *>(visibleItems.takeLast());
4037 insertResult->sizeChangesAfterVisiblePos -= nvItem->size() + spacing;
4038 addedItems->removeOne(nvItem);
4039#if QT_CONFIG(quick_viewtransitions)
4040 if (nvItem->transitionScheduledOrRunning())
4041 nvItem->setPosition(prevPos + (nvItem->index - prevItem->index) * averageSize);
4049 updateVisibleIndex();
4051 return visibleAffected;