QML ListView如何估计它的contentItem的高度/宽度

时间:2017-03-14 08:16:31

标签: algorithm qt listview qml

我想知道ListView如何估算它contentItem的高度/宽度,尽管代表是Component,你不能问,并且大小可能因委托实例而异。

  • 它不使用当前实例的平均大小 否则,在示例1 中,如果按下一个元素,如果计算所有实例,则估计的大小将 3055.5 ;如果仅计算所有实例,则 3125 视图被计算在内。它估计 2845
  • 它不使用所有当前实例的最大大小 如果按下一个元素,估计的大小将 7500 。如果仅考虑非实例化元素的最大高度,则 6350
  • 它不使用所有当前实例的最小大小 估计肯定会很小。

即使您知道正确的尺寸,也无法提供帮助,因为在示例1 中我们知道正确的contentHeight 2500 如果没有按下任何内容, 2650 如果按下了某些内容。在示例2 中,右contentHeight 1225 ,但手动设置该值是没有用的,因为它很快就会被覆盖。

示例1:

ListView {
    id: lv1
    width: 200
    height: 500
    model: 50
    onContentHeightChanged: console.log('estimated contentHeight', contentHeight)
    delegate: Rectangle {
        width: 200
        height: ma.pressed ? 150 : 50
        border.color: 'black'
        Text {
            anchors.centerIn: parent
            text: index
        }

        MouseArea {
            id: ma
            anchors.fill: parent
        }
    }
}

示例2:

ListView {
    id: lv1
    width: 200
    height: 500
    model: 50
    onContentHeightChanged: console.log('estimated contentHeight', contentHeight)
    delegate: Rectangle {
        width: 200
        height: index
        border.color: 'black'
        Text {
            anchors.centerIn: parent
            text: index + ' ' + ((index * (index + 1)) / 2)
        }
    }
}

1 个答案:

答案 0 :(得分:3)

我不知道。让我们来看看源代码。 :)

查看设置contentWidthcontentHeight的代码here's

void QQuickItemViewPrivate::updateViewport()
{
    Q_Q(QQuickItemView);
    qreal extra = headerSize() + footerSize();
    qreal contentSize = isValid() || !visibleItems.isEmpty() ? (endPosition() - startPosition()) : 0.0;
    if (layoutOrientation() == Qt::Vertical)
        q->setContentHeight(contentSize + extra);
    else
        q->setContentWidth(contentSize + extra);
}

startPosition()endPosition()函数已声明为here

qreal QQuickItemViewPrivate::startPosition() const
{
    return isContentFlowReversed() ? -lastPosition() : originPosition();
}

qreal QQuickItemViewPrivate::endPosition() const
{
    return isContentFlowReversed() ? -originPosition() : lastPosition();
}

QQuickListView originPosition()lastPosition()的实施都是here

qreal QQuickListViewPrivate::originPosition() const
{
    qreal pos = 0;
    if (!visibleItems.isEmpty()) {
        pos = (*visibleItems.constBegin())->position();
        if (visibleIndex > 0)
            pos -= visibleIndex * (averageSize + spacing);
    }
    return pos;
}

qreal QQuickListViewPrivate::lastPosition() const
{
    qreal pos = 0;
    if (!visibleItems.isEmpty()) {
        int invisibleCount = INT_MIN;
        int delayRemovedCount = 0;
        for (int i = visibleItems.count()-1; i >= 0; --i) {
            if (visibleItems.at(i)->index != -1) {
                // Find the invisible count after the last visible item with known index
                invisibleCount = model->count() - (visibleItems.at(i)->index + 1 + delayRemovedCount);
                break;
            } else if (visibleItems.at(i)->attached->delayRemove()) {
                ++delayRemovedCount;
            }
        }
        if (invisibleCount == INT_MIN) {
            // All visible items are in delayRemove state
            invisibleCount = model->count();
        }
        pos = (*(--visibleItems.constEnd()))->endPosition();
        if (invisibleCount > 0)
            pos += invisibleCount * (averageSize + spacing);
    } else if (model && model->count()) {
        pos = (model->count() * averageSize + (model->count()-1) * spacing);
    }
    return pos;
}

averageSize似乎是here计算的:

void QQuickListViewPrivate::updateAverage()
{
    if (!visibleItems.count())
        return;
    qreal sum = 0.0;
    for (int i = 0; i < visibleItems.count(); ++i)
        sum += visibleItems.at(i)->size();
    averageSize = qRound(sum / visibleItems.count());
}

该函数由QQuickListViewPrivate::visibleItemsChanged()调用,由QQuickItemViewPrivate::refill()调用,在整个地方都被调用。基本上每当与视图或其项目相关的任何更改时。

visibleItems.at(i)->size() pretty much equivalentQQuickItem::width() / QQuickItem::height()

inline qreal itemWidth() const { return item ? item->width() : 0; }
inline qreal itemHeight() const { return item ? item->height() : 0; }

从我所看到的,它或多或少取得了视图中可见的每个项目的高度(可能等同于&#34;当前实例化&#34;),将它们加在一起然后除以该总和按可见项目的数量。您可以通过添加以下调试输出来确认:

$ git diff
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 0351077..acfb88a 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -1296,6 +1296,7 @@ void QQuickListViewPrivate::updateAverage()
     for (FxViewItem *item : qAsConst(visibleItems))
         sum += item->size();
     averageSize = qRound(sum / visibleItems.count());
+    qDebug() << "sum" << sum << "visibleItems.count()" << visibleItems.count();
 }

 qreal QQuickListViewPrivate::headerSize() const

点击项目之前的输出:

qml: estimated contentHeight 5000
sum 550 visibleItems.count() 11
qml: estimated contentHeight 2500
sum 850 visibleItems.count() 17

按下第一项后:

sum 850 visibleItems.count() 15
qml: estimated contentHeight 2845

所以我会说

  

它不使用当前实例的平均大小。

在某种程度上是不正确的。如果您真的想知道区别是什么,那么您需要进一步了解代码。