0

I have a C++ model derived from QAbstractListModel which I am using in a QML ListView

ListView {
    id: listView
    populate: Transition {
        id: addTrans
        SequentialAnimation {
            PauseAnimation {
                duration: (addTrans.ViewTransition.index -
                           addTrans.ViewTransition.targetIndexes[0]) * 100
            }
            NumberAnimation { property: "scale"; from: 0; to: 1 }
        }
    }

    anchors.fill: parent
    delegate: listDelegate
    model: newsModel
}

I tried to add an animation for when the list is populated, but it doesn't work. So what I did was I tried to change populate to add and the animation is triggered, however the problem is that that each item is already in the list when the animation starts: in other words, instead of having an empty list to which items are added, I have a full list of elements that are then individually animated. I have tried also following this suggestion but it doesn't work.

EDIT: as requested I am providing a minimal working example to reproduce my problem. The problem can be reproduced with the following:

#include <QObject>
#include <QQmlObjectListModel.h>

class Item : public QObject{
    Q_OBJECT
    Q_PROPERTY(QString name READ name NOTIFY nameChanged)

public:
    Item(QObject* parent = nullptr): QObject(parent)
    {
    }
    QString name() const{
        return mName;
    }
    void setName(QString const &name){
        if(mName != name){
            mName = name;
            emit nameChanged();
        }
    }
signals:
    void nameChanged();
private:
    QString mName;
};

class DataManager : public QObject{
    Q_OBJECT
    Q_PROPERTY(QQmlObjectListModel<Item>* itemsModel READ itemsModel CONSTANT)
public:
    DataManager(){
        mItemsModel = new QQmlObjectListModel<Item>(this);
        qRegisterMetaType<QQmlObjectListModel<Item>*>("QQmlObjectListModel<Item>*");
        // I have also tried to add items from here, but the result is even worse
//        for(int i = 0; i < 20; i++){
//            addItem(QString::number(i));
//        }
    }
    QQmlObjectListModel<Item>* itemsModel(){
        return mItemsModel;
    }
    Q_INVOKABLE void addItem(QString const &name){
        Item* item = new Item(mItemsModel);
        item->setName(name);
        mItemsModel->append(item);
    }
private:
    QQmlObjectListModel<Item>* mItemsModel;
};

Then in qml:

import QtQuick 2.12
import QtQuick.Controls 2.5

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Scroll")

    ScrollView {
        anchors.fill: parent

        ListView {
            width: parent.width
// dataManager is a context property set via c++
            model: dataManager.itemsModel
            populate: Transition {
                id: popTrans
                SequentialAnimation {
                    PauseAnimation {
                        duration: (popTrans.ViewTransition.index -
                                   popTrans.ViewTransition.targetIndexes[0]) * 100
                    }
                    NumberAnimation { property: "scale"; from: 0; to: 1 }
                }
            }
            add: Transition {
                id: addTrans
                SequentialAnimation {
                    PauseAnimation {
                        duration: (addTrans.ViewTransition.index -
                                   addTrans.ViewTransition.targetIndexes[0]) * 100
                    }
                    NumberAnimation { property: "scale"; from: 0; to: 1 }
                }
            }
            delegate: ItemDelegate {
                text: "Item" + name
                width: parent.width
            }
        }
    }
    Component.onCompleted: {
        var p;
        for(p=0; p < 20; p++){
            dataManager.addItem(p)
        }
    }
}

The QQmlObjectListModel is a helper class which I borrowed from here

reckless
  • 741
  • 12
  • 53
  • Show us how the `newsModel` is being popuplated. From the suggestion (and the Qt docs) I think you might use the `populate` wrong, but we cannot see as your example does not show (And also, your wording doesn't clearly reveal) – Amfasis Aug 20 '19 at 08:37
  • @Amfasis I added more details to my question – reckless Aug 20 '19 at 20:43
  • I have created an example myself as well, but when I add the `populate` transition, the whole `ListView` gets messed up, the first item is animated, but the other are just there, and they end up at 0,0 if you don't explicitly set the position. I think the `populate` animation is buggy. Also [Qt docs](https://doc.qt.io/qt-5/qml-qtquick-viewtransition.html) don't give a example for `populate` and I think you're [not alone](https://stackoverflow.com/questions/49772386/qml-listview-populate-opacity-animation) – Amfasis Aug 21 '19 at 07:20
  • I only got it working correctly when using a **very ugly** solution, set the model using a timer (got this thought after reading https://stackoverflow.com/a/32389005/1228771). See my gist: https://gist.github.com/amfasis/8f35d1b1c09a3f5ef06cd042f83be109 – Amfasis Aug 21 '19 at 07:31
  • @Amfasis yeah it seems like a bug that apparently will be fixed in 5.13.1 https://bugreports.qt.io/browse/QTBUG-76487?jql=text%20~%20%22listview%20populate%22 – reckless Aug 21 '19 at 10:02
  • Yeah I thought so :-) good they will fix it! – Amfasis Aug 21 '19 at 11:07

1 Answers1

0

I am not sure what you want exactly, but I hope my code help you.

    populate: Transition {
        id: addTrans
        SequentialAnimation {
            PropertyAction {
                property: "visible"
                value: false
            }
            PauseAnimation {
                duration: (addTrans.ViewTransition.index -
                           addTrans.ViewTransition.targetIndexes[0]) * 100
            }
            PropertyAction {
                property: "visible"
                value: true
            }
            NumberAnimation { property: "scale"; from: 0; to: 1 }
        }
    }
DenimPowell
  • 1,073
  • 7
  • 14