Home > Software engineering >  How to animate a subset of items instantiated by Repeater one after another in Qt QML?
How to animate a subset of items instantiated by Repeater one after another in Qt QML?

Time:11-19

Is there a standard QML component using which several items created in Repeater can be animated one after the other with some delay (i.e. not simultaneously)? So far I could only come up with a Timer based solution like below:

import QtQuick 6.3

Item {
    width: 600; height: 400

    Row {
        anchors.fill: parent
        spacing: 5
        Repeater {
            id: _repeater
            anchors.fill: parent
            model: 10
            delegate: Rectangle {
                id: _rect
                width: 50; height: 50
                color: "green"
                function animate() {_anim.start()}
                SequentialAnimation {
                    id: _anim
                    NumberAnimation {target: _rect; property: "height"; from: 50; to: 150}
                    NumberAnimation {target: _rect; property: "height"; from: 150; to: 50}
                }
            }
        }
    }

    Timer {
        id: _timer
        property var indexes
        repeat: true
        interval: 150
        onTriggered: {
            if (indexes.length !== 0) {
                 _repeater.itemAt(indexes.shift()).animate()
            } else
                stop()
        }
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            _timer.indexes = [1, 2, 3, 4]
            _timer.start() 
        }
    }
}

CodePudding user response:

I would use Timeline for that, this is a small example:

    import QtQuick
    import QtQuick.Timeline
    import QtQuick.Controls
    
    Window {
        width: 500
        height: 400
        visible: true
    
        Component {
            id: keyframeComponent
            KeyframeGroup {
                property int startFrame: 0
                property int endFrame: 0
                property int startValue: 0
                property: "height"
                Keyframe { frame: startFrame; value: startValue }
                Keyframe { frame: (startFrame   endFrame) / 2; value: 300 }
                Keyframe { frame: endFrame; value: startValue }
            }
        }
    
        Row {
            width: parent.width
            height: 300
            spacing: 1
            Repeater {
                model: 10
                Rectangle {
                    id: rect
                    width: 49
                    height: Math.round(Math.random() * parent.height)
                    color: "orange"
                    Component.onCompleted: {
                        var startFrame = Math.round(Math.random() * 100);
                        var endFrame = Math.round(Math.random() * 100);
                        if(startFrame > endFrame)
                        {
                            var temp = endFrame;
                            endFrame = startFrame;
                            startFrame = temp;
                        }
                        var group = keyframeComponent.createObject(timelineAnimation, {
                                                                       startFrame: startFrame,
                                                                       endFrame: endFrame,
                                                                       startValue: rect.height,
                                                                       target: rect });
                        timeline.keyframeGroups.push(group);
                    }
                }
            }
        }
    
        Button {
            anchors.bottom: parent.bottom
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.bottomMargin: 10
            text: "Start"
            onClicked: {
                timelineAnimation.start();
            }
        }
    
        Timeline {
            id: timeline
            startFrame: 0
            endFrame: 100
            enabled: true
    
            animations: [
                TimelineAnimation {
                    duration: 1000;
                    from: 0;
                    to: 100;
                    running: false;
                    id: timelineAnimation
                }
            ]
            keyframeGroups: []
        }
    }

Here I create KeyframeGroup dynamically but you can create that statically of course.

CodePudding user response:

Since you're already using SequentialAnimation and NumberAnimation you do not need to use Timer. You just insert a dummy animation and set a duration to help delay your animation, e.g.

import QtQuick
import QtQuick.Controls
Page {
    Repeater {
        model: 10
        Rectangle {
            id: _rect
            color: "green"
            x: index * 60   50
            y: 50
            width: 50
            height: 50
            property real dummy: 0
            SequentialAnimation {
                running: true
                NumberAnimation {target: _rect; property: "dummy"; from: 50; to: 150; duration: index * 100 }
                NumberAnimation {target: _rect; property: "height"; from: 50; to: 150}
                NumberAnimation {target: _rect; property: "height"; from: 150; to: 50}
            }
        }
    }
}

You can Try it Online!

CodePudding user response:

Since you're already using SequentialAnimation and NumberAnimation you do not need to use Timer. You just insert a dummy animation and set a duration to help delay your animation, e.g.

import QtQuick
import QtQuick.Controls
Page {
    id: page
    background: Rectangle { color: "#848895" }
    Repeater {
        model: 10
        Rectangle {
            id: _rect
            border.color: "white"
            color: Qt.lighter("green", 1.0   index * 0.3)
            x: index * 60   50
            y: 50
            width: 50
            height: 50
            property real dummy: 0
            SequentialAnimation {
                running: true
                NumberAnimation {target: _rect; property: "dummy"; from: 50; to: 150; duration: index * 100 }
                NumberAnimation {target: _rect; property: "height"; from: 50; to: 150}
                NumberAnimation {target: _rect; property: "height"; from: 150; to: 50}
            }
        }
    }
}

You can Try it Online!

  • Related