fix: use visible height to calc contentHeight

This commit is contained in:
2 * r + 2 * t 2026-04-03 16:04:51 +11:00
parent 051b8caee6
commit 916b702562
3 changed files with 59 additions and 4 deletions

View file

@ -73,6 +73,7 @@ LazyListView {
} }
LazyListView.preferredHeight: closed ? 0 : notifInner.nonAnimHeight LazyListView.preferredHeight: closed ? 0 : notifInner.nonAnimHeight
LazyListView.visibleHeight: notifInner.implicitHeight
implicitHeight: notifInner.implicitHeight implicitHeight: notifInner.implicitHeight
opacity: LazyListView.removing || closed || LazyListView.adding ? 0 : 1 opacity: LazyListView.removing || closed || LazyListView.adding ? 0 : 1

View file

@ -22,6 +22,17 @@ void LazyListViewAttached::setPreferredHeight(qreal height) {
emit preferredHeightChanged(); emit preferredHeightChanged();
} }
qreal LazyListViewAttached::visibleHeight() const {
return m_visibleHeight;
}
void LazyListViewAttached::setVisibleHeight(qreal height) {
if (qFuzzyCompare(m_visibleHeight, height))
return;
m_visibleHeight = height;
emit visibleHeightChanged();
}
bool LazyListViewAttached::adding() const { bool LazyListViewAttached::adding() const {
return m_adding; return m_adding;
} }
@ -210,6 +221,22 @@ qreal LazyListView::delegateHeight(QQuickItem* item) {
return item->implicitHeight(); return item->implicitHeight();
} }
qreal LazyListView::delegateVisibleHeight(QQuickItem* item) {
if (!item)
return 0;
auto* attached = qobject_cast<LazyListViewAttached*>(
qmlAttachedPropertiesObject<LazyListView>(item, false));
if (attached) {
if (attached->visibleHeight() >= 0)
return attached->visibleHeight();
if (attached->preferredHeight() >= 0)
return attached->preferredHeight();
}
return item->implicitHeight();
}
// --- Add Animation --- // --- Add Animation ---
int LazyListView::addDuration() const { int LazyListView::addDuration() const {
@ -388,15 +415,33 @@ void LazyListView::updatePolish() {
// --- Layout Engine --- // --- Layout Engine ---
void LazyListView::relayout() { void LazyListView::relayout() {
// Layout positioning uses preferredHeight (final/non-animated)
qreal y = 0; qreal y = 0;
for (auto& record : m_layout) { for (auto& record : m_layout) {
record.targetY = y; record.targetY = y;
y += (record.heightKnown ? record.height : effectiveEstimatedHeight()) + m_spacing; y += (record.heightKnown ? record.height : effectiveEstimatedHeight()) + m_spacing;
} }
const qreal newHeight = m_layout.isEmpty() ? 0 : y - m_spacing; // Content height tracks actual visible heights so scrolling follows animations
if (!qFuzzyCompare(m_contentHeight, newHeight)) { qreal visY = 0;
m_contentHeight = newHeight; for (int i = 0; i < static_cast<int>(m_layout.size()); ++i) {
qreal h;
if (m_delegates.contains(i) && m_delegates[i].item)
h = delegateVisibleHeight(m_delegates[i].item);
else
h = m_layout[i].heightKnown ? m_layout[i].height : effectiveEstimatedHeight();
visY += h + m_spacing;
}
qreal maxBottom = m_layout.isEmpty() ? 0 : visY - m_spacing;
// Account for dying delegates still visually present
for (const auto& dying : m_dyingDelegates) {
if (dying.item)
maxBottom = std::max(maxBottom, dying.item->y() + delegateVisibleHeight(dying.item));
}
if (!qFuzzyCompare(m_contentHeight, maxBottom)) {
m_contentHeight = maxBottom;
emit contentHeightChanged(); emit contentHeightChanged();
} }
} }
@ -591,12 +636,14 @@ LazyListView::DelegateEntry LazyListView::createDelegate(int modelIndex) {
// Watch implicitHeight as fallback // Watch implicitHeight as fallback
connect(entry.item, &QQuickItem::implicitHeightChanged, this, onHeightChanged); connect(entry.item, &QQuickItem::implicitHeightChanged, this, onHeightChanged);
// Watch attached preferredHeight if the delegate uses it // Watch attached properties if the delegate uses them
auto* attached = qobject_cast<LazyListViewAttached*>( auto* attached = qobject_cast<LazyListViewAttached*>(
qmlAttachedPropertiesObject<LazyListView>(entry.item, false)); qmlAttachedPropertiesObject<LazyListView>(entry.item, false));
if (attached) { if (attached) {
entry.attachedConnection = connect(attached, &LazyListViewAttached::preferredHeightChanged, entry.attachedConnection = connect(attached, &LazyListViewAttached::preferredHeightChanged,
this, onHeightChanged); this, onHeightChanged);
connect(attached, &LazyListViewAttached::visibleHeightChanged,
this, [this] { polish(); });
} }
return entry; return entry;

View file

@ -18,6 +18,7 @@ class LazyListViewAttached : public QObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(qreal preferredHeight READ preferredHeight WRITE setPreferredHeight NOTIFY preferredHeightChanged) Q_PROPERTY(qreal preferredHeight READ preferredHeight WRITE setPreferredHeight NOTIFY preferredHeightChanged)
Q_PROPERTY(qreal visibleHeight READ visibleHeight WRITE setVisibleHeight NOTIFY visibleHeightChanged)
Q_PROPERTY(bool adding READ adding NOTIFY addingChanged) Q_PROPERTY(bool adding READ adding NOTIFY addingChanged)
Q_PROPERTY(bool removing READ removing NOTIFY removingChanged) Q_PROPERTY(bool removing READ removing NOTIFY removingChanged)
@ -27,6 +28,9 @@ public:
[[nodiscard]] qreal preferredHeight() const; [[nodiscard]] qreal preferredHeight() const;
void setPreferredHeight(qreal height); void setPreferredHeight(qreal height);
[[nodiscard]] qreal visibleHeight() const;
void setVisibleHeight(qreal height);
[[nodiscard]] bool adding() const; [[nodiscard]] bool adding() const;
void setAdding(bool adding); void setAdding(bool adding);
@ -35,11 +39,13 @@ public:
signals: signals:
void preferredHeightChanged(); void preferredHeightChanged();
void visibleHeightChanged();
void addingChanged(); void addingChanged();
void removingChanged(); void removingChanged();
private: private:
qreal m_preferredHeight = -1; qreal m_preferredHeight = -1;
qreal m_visibleHeight = -1;
bool m_adding = false; bool m_adding = false;
bool m_removing = false; bool m_removing = false;
}; };
@ -209,6 +215,7 @@ private:
[[nodiscard]] QRectF effectiveViewport() const; [[nodiscard]] QRectF effectiveViewport() const;
[[nodiscard]] qreal effectiveEstimatedHeight() const; [[nodiscard]] qreal effectiveEstimatedHeight() const;
[[nodiscard]] static qreal delegateHeight(QQuickItem* item); [[nodiscard]] static qreal delegateHeight(QQuickItem* item);
[[nodiscard]] static qreal delegateVisibleHeight(QQuickItem* item);
void trackHeight(qreal height); void trackHeight(qreal height);
void untrackHeight(qreal height); void untrackHeight(qreal height);