Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

SwipeView with dynamic "interactive" breaks "currentIndex" binding



  • Hi,

    I'm trying to create a SwipeView where the first page has the interactive property false, while the others have it enabled. The effect that I'm trying to achieve is to have the main page with a link to the others, but the others can only go back to the main page (like the iOS settings menu).

    The issue is that after the first change page, the currentIndex property loses binding causing the SwipeView to break.

    Here's the application output:

    qrc:/main.qml:10:5: QML SwipeView: Binding loop detected for property "currentIndex"
    file:///home/rcc/Qt/5.12.6/gcc_64/qml/QtQuick/Controls.2/SwipeView.qml:49:18: QML ListView: Binding loop detected for property "currentIndex"
    

    and here's the default swipe view application (QtCreator -> New Project -> Qt Quick Application - Swipe) main.qml:

    import QtQuick 2.12
    import QtQuick.Controls 2.5
    
    ApplicationWindow {
        visible: true
        width: 640
        height: 480
        title: qsTr("Tabs")
    
        SwipeView {
            id: swipeView
            anchors.fill: parent
            currentIndex: tabBar.currentIndex
    
            interactive: false
    
            onCurrentIndexChanged: {
                if (currentIndex === 0) {
                    interactive = false
                } else {
                    interactive = true
                }
            }
    
            Page1Form {}
    
            Page2Form {}
        }
    
        footer: TabBar {
            id: tabBar
            currentIndex: swipeView.currentIndex
    
            TabButton {
                text: qsTr("Page 1")
            }
            TabButton {
                text: qsTr("Page 2")
            }
        }
    }
    

    To reproduce the bug:

    • Click on Page 2.
    • Swipe left.
    • Click again on Page 2.

    Any suggestions to solve this issue?



  • You have binding loop, as output says. You need to remove currentIndex: tabBar.currentIndex binding from your SwipeView and control its index by clicking on tab button, like this:

        SwipeView {
            id: swipeView
            anchors.fill: parent
            interactive: currentIndex
    
            Rectangle {color: "red"; opacity: 0.5}
            Rectangle {color: "green"; opacity: 0.5}
            Rectangle {color: "blue"; opacity: 0.5}
        }
    
        footer: TabBar {
            id: tabBar
            currentIndex: swipeView.currentIndex
    
            TabButton {
                text: qsTr("Page 1")
                onClicked: swipeView.setCurrentIndex(TabBar.index)
            }
            TabButton {
                text: qsTr("Page 2")
                onClicked: swipeView.setCurrentIndex(TabBar.index)
            }
        }
    


  • @IntruderExcluder said in SwipeView with dynamic "interactive" breaks "currentIndex" binding:

    You have binding loop, as output says. You need to remove currentIndex: tabBar.currentIndex binding from your SwipeView and control its index by clicking on tab button, like this:

        SwipeView {
            id: swipeView
            anchors.fill: parent
            interactive: currentIndex
    
            Rectangle {color: "red"; opacity: 0.5}
            Rectangle {color: "green"; opacity: 0.5}
            Rectangle {color: "blue"; opacity: 0.5}
        }
    
        footer: TabBar {
            id: tabBar
            currentIndex: swipeView.currentIndex
    
            TabButton {
                text: qsTr("Page 1")
                onClicked: swipeView.setCurrentIndex(TabBar.index)
            }
            TabButton {
                text: qsTr("Page 2")
                onClicked: swipeView.setCurrentIndex(TabBar.index)
            }
        }
    

    I've done what you say, but the problem is still here:

    import QtQuick 2.12
    import QtQuick.Controls 2.5
    
    ApplicationWindow {
        visible: true
        width: 640
        height: 480
        title: qsTr("Tabs")
    
        SwipeView {
            id: swipeView
            anchors.fill: parent
    
            interactive: currentIndex
    
            Rectangle {
                color: "red"
                opacity: 0.5
            }
            Rectangle {
                color: "green"
                opacity: 0.5
            }
            Rectangle {
                color: "blue"
                opacity: 0.5
            }
        }
    
        footer: TabBar {
            id: tabBar
            currentIndex: swipeView.currentIndex
    
            TabButton {
                text: qsTr("Page 1")
                onClicked: swipeView.setCurrentIndex(TabBar.index)
            }
            TabButton {
                text: qsTr("Page 2")
                onClicked: swipeView.setCurrentIndex(TabBar.index)
            }
        }
    }
    

    Error:

    file:///home/rcc/Qt/5.12.6/gcc_64/qml/QtQuick/Controls.2/SwipeView.qml:49:18: QML ListView: Binding loop detected for property "currentIndex"
    

    By the way, I'm using Qt 5.12.6 Linux desktop.



  • I'm linking the StackOverflow question and the Qt Bug

    This is the workaround suggested:

            onCurrentIndexChanged: {
                if (currentIndex === 0) {
                    Qt.callLater(function() { interactive = false })
                } else {
                    Qt.callLater(function() { interactive = true })
                }
            }