具有“填充”过渡的 QML 中继器

Posted

技术标签:

【中文标题】具有“填充”过渡的 QML 中继器【英文标题】:QML Repeater with 'populate' transition 【发布时间】:2021-09-26 16:05:26 【问题描述】:

我正在尝试使用中继器复制ListView.populate: Transition ..。不幸的是,由于可怕的性能问题,我不能简单地使用ListView,所以只能使用Repeater

我正在寻找的过渡很简单,实际上正是 ListView Documentation 中使用的过渡,即我的中继器加载时,每个条目从顶部 Here is a working example of my desired outcome 向下“级联”

我尝试让我们使用Behavior on y NumberAnimation duration: 300 ,但是中继器似乎没有在创建时修改y。我还将它绑定到 Component.onCompleted 处理程序中,以查看它也触发了但失败了。

我的问题是

如何为Repeater 创建类似于ListView.populate 属性的y 动画?

【问题讨论】:

【参考方案1】:

显而易见的替代方法是将 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,但如果您不喜欢这种行为,可以更改它。

【讨论】:

以上是关于具有“填充”过渡的 QML 中继器的主要内容,如果未能解决你的问题,请参考以下文章

QML ListElement 传递字符串列表

QML:在中继器上调用 itemAt 返回 null

qml 使用中继器从 Qlist 绘制折线图

更改模型后未正确绘制 QML 中继器

QML:如何通过拖放重新排序中继器项目?里面有一些工作代码

QML 使用中继器和委托,显示旧列表