显而易见的替代方法是将 QML Column 与 Repeater 一起使用,但 Column 是一个定位器,将直接设置其子级 y 位置而不使用 setProperty。出于这个原因,我做了类似的事情,但这次让 QML 系统知道属性更改。
MyColumn.h
#pragma once
#include <QQuickItem>
class MyColumn : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged)
public:
explicit MyColumn(QQuickItem* parent = nullptr);
~MyColumn();
qreal spacing() const;
void setSpacing(qreal r);
void positionItems();
void componentComplete() override;
void itemChange(ItemChange, const ItemChangeData&) override;
Q_SIGNALS:
void spacingChanged();
public /*slots*/:
void onChildImplicitWidthChanged();
void onChildImplicitHeightChanged();
private:
qreal mSpacing;
};
MyColumn.cpp
#include "MyColumn.h"
MyColumn::MyColumn(QQuickItem* parent) : QQuickItem{ parent }, mSpacing{ 0.0 }
{
setFlag(ItemHasContents, true);
}
MyColumn::~MyColumn()
{
}
qreal MyColumn::spacing() const
{
return mSpacing;
}
void MyColumn::setSpacing(qreal s)
{
if (mSpacing == s) return;
mSpacing = s;
Q_EMIT spacingChanged();
if (isComponentComplete())
positionItems();
}
void MyColumn::positionItems()
{
qreal maxImplicitWidth = 0.0;
qreal totalImplicitHeight = 0.0;
QList<QQuickItem*> children = childItems();
for (int i = 0; i < children.count(); ++i) {
QQuickItem* child = children.at(i);
//child->setY(totalImplicitHeight);
child->setProperty("y", totalImplicitHeight);
if (child->implicitWidth() > maxImplicitWidth)
maxImplicitWidth = child->implicitWidth();
if (child->implicitHeight() > 0) {
totalImplicitHeight += child->implicitHeight();
totalImplicitHeight += mSpacing;
}
}
totalImplicitHeight -= mSpacing;
setImplicitWidth(maxImplicitWidth);
setImplicitHeight(totalImplicitHeight);
}
void MyColumn::componentComplete()
{
positionItems();
QQuickItem::componentComplete();
}
void MyColumn::onChildImplicitWidthChanged()
{
positionItems();
}
void MyColumn::onChildImplicitHeightChanged()
{
positionItems();
}
void MyColumn::itemChange(ItemChange change, const ItemChangeData& value)
{
if (change == ItemChildAddedChange)
{
QObject::connect(value.item, &QQuickItem::implicitWidthChanged, this, &MyColumn::onChildImplicitWidthChanged);
QObject::connect(value.item, &QQuickItem::implicitHeightChanged, this, &MyColumn::onChildImplicitHeightChanged);
}
else if(change == ItemChildRemovedChange)
{
positionItems();
}
QQuickItem::itemChange(change, value);
}
例如,在 main.cpp 中,您必须将此类型注册为 QML 中的可创建类型
qmlRegisterType<MyColumn>("MyColumn", 1, 0, "MyColumn");
这里是相关的QML代码sn-p:
//...
import MyColumn 1.0
//...
MyColumn {
Repeater {
model: 10
Rectangle {
implicitWidth: 200
implicitHeight: 30
color: "red"
border.width: 1
Behavior on y { NumberAnimation { duration: 1000; easing.type: Easing.OutQuad; } }
}
}
}
请注意,我的实现适用于implicitWidth,但如果您不喜欢这种行为,可以更改它。