Disable swiping multi items on SwipeDelegate

Viewed 1022

By default SwipeDelegate allows for swiping multi items like below image:

enter image description here

As you can see, multi swipe items are open at a time and i want only one open item at a time, means if you open item #1, by opening item #2, item #1 should close. how can i achieve this?

Sample code for a ListView with SwipeDelegate:

ListView {
    id: listView
    anchors.fill: parent

    delegate: SwipeDelegate {
        id: delegate

        text: modelData
        width: parent.width

        swipe.right: Rectangle {
            width: parent.width
            height: parent.height

            Label {
                text: qsTr("SOME ACTION BUTTON")

                padding: 20
                anchors.fill: parent
            }

        }
    }

    model: ListModel {
        id: listModel
        ListElement { text: "Lorem ipsum dolor sit amet" }
        ListElement { text: "Curabitur sit amet risus" }
        ListElement { text: "Suspendisse vehicula nisi" }
        ListElement { text: "Mauris imperdiet libero" }
        ListElement { text: "Sed vitae dui aliquet augue" }
        ListElement { text: "Praesent in elit eu nulla" }
        ListElement { text: "Etiam vitae magna" }
        ListElement { text: "Pellentesque eget elit euismod" }
        ListElement { text: "Nulla at enim porta" }
        ListElement { text: "Fusce tincidunt odio" }
        ListElement { text: "Ut non ex a ligula molestie" }
        ListElement { text: "Nam vitae justo scelerisque" }
        ListElement { text: "Vestibulum pulvinar tellus" }
        ListElement { text: "Quisque dignissim leo sed gravida" }
    }


    ScrollIndicator.vertical: ScrollIndicator { }
}
2 Answers

Here's how I would do this:

import QtQuick 2.9
import QtQuick.Controls 2.3
import QtGraphicalEffects 1.0

ApplicationWindow {
    id: window
    width: 800
    height: 600
    visible: true

    ListView {
        id: listView
        anchors.fill: parent

        ButtonGroup {
            buttons: listView.contentItem.children
        }

        delegate: SwipeDelegate {
            id: delegate

            checkable: true
            text: modelData
            width: parent.width
            checked: swipe.complete
            onCheckedChanged: if (!checked) swipe.close()

            swipe.right: Rectangle {
                width: parent.width
                height: parent.height
                color: "#666"

                Label {
                    text: qsTr("SOME ACTION BUTTON")
                    color: "white"
                    leftPadding: 20
                    anchors.verticalCenter: parent.verticalCenter
                }
            }
        }

        model: ListModel {
            id: listModel
            ListElement { text: "Lorem ipsum dolor sit amet" }
            ListElement { text: "Curabitur sit amet risus" }
            ListElement { text: "Suspendisse vehicula nisi" }
            ListElement { text: "Mauris imperdiet libero" }
            ListElement { text: "Sed vitae dui aliquet augue" }
            ListElement { text: "Praesent in elit eu nulla" }
            ListElement { text: "Etiam vitae magna" }
            ListElement { text: "Pellentesque eget elit euismod" }
            ListElement { text: "Nulla at enim porta" }
            ListElement { text: "Fusce tincidunt odio" }
            ListElement { text: "Ut non ex a ligula molestie" }
            ListElement { text: "Nam vitae justo scelerisque" }
            ListElement { text: "Vestibulum pulvinar tellus" }
            ListElement { text: "Quisque dignissim leo sed gravida" }
        }


        ScrollIndicator.vertical: ScrollIndicator { }
    }
}

ButtonGroup ensures that only one "button" (SwipeDelegate is derived from AbstractButton) can be checked at a time. SwipeDelegate has no visual effects to represent the checked state, so we can safely use it to keep track of which one should be open. We still need to close the previously open delegate though, so that's where the

onCheckedChanged: if (!checked) swipe.close()

comes in.

swipedelegate

Inspired by the answer with the ButtonGroup, here's my solution which does not require to modify the delegates:

SwipeDelegateGroup.qml

import QtQuick 2.9
import QtQuick.Controls 2.2

Item {
    id: swipeGroup

    property ListView listView: parent
    QtObject {
        id: d
        property var delegates: swipeGroup.listView.contentItem.children
        property var delegateCache: []

        onDelegatesChanged: {
            for (var i = 0; i < d.delegates.length; i++) {
                var thisItem = d.delegates[i];
                if (!thisItem.hasOwnProperty("swipe")) {
                    continue;
                }
                if (d.delegateCache.indexOf(thisItem) < 0) {
                    d.delegateCache.push(thisItem);

                    thisItem.Component.destruction.connect(function() {
                        d.delegateCache.splice(d.delegateCache.indexOf(thisItem), 1)
                    })

                    thisItem.swipe.opened.connect(function() {
                        for (var j = 0; j < d.delegates.length; j++) {
                            var otherItem = d.delegates[j];
                            if (thisItem === otherItem) {
                                continue;
                            }
                            if (!otherItem.hasOwnProperty("swipe")) {
                                continue;
                            }
                            otherItem.swipe.close();
                        }
                    })
                }
            }
        }
    }
}

Then just put this into the ListView like this:

ListView {

    SwipeDelegateGroup {}

    delegate: SwipeDelegate {
        ...
    }
}
Related