首页 文章

QML:同步滚动多个ListView

提问于
浏览
3

我想要一个(垂直)ListView与(水平)ListView委托 .

水平代表应同步滚动 . 为此,我将一个Flickable放在ListViews的顶部,并将水平ListView的contentX绑定到Flickable的contentX(对于垂直ListView的contentY也是如此)(注意:Here描述了一个不同的方法)同步ListView滚动,但这似乎在移动设备上有性能问题)

下面的代码有点工作,但仍然有以下问题

  • 我没有得到矩形中的onClicked(当我删除顶部Flickable时我确实得到了它)

  • 我想要水平轻弹或垂直轻弹,但不能同时进行 . 我可以通过设置 flickableDirection: Flickable.HorizontalFlick 来限制顶部Flickable的轻弹,但是我似乎可以't flick vertically anymore (I was hoping that the Flickable would pass on unused mouse events to the vertical ListView but this doesn' t)

关于如何解决这些问题的建议?

任何帮助赞赏!

import QtQuick 2.0

Item {
    id: main
    visible: true
    width: 600
    height: 600

    ListView {
        id: verticalList
        width: parent.width;
        height: parent.height;
        contentY : flickable.contentY
        anchors.fill: parent
        spacing: 10
        orientation: ListView.Vertical
        model: 100
        delegate:
            ListView {
                id: horizontalList
                width: parent.width;
                height: 100;
                contentX : flickable.contentX
                spacing: 10
                orientation: ListView.Horizontal
                model: 20
                property var verticalIndex : index
                delegate:
                    Rectangle
                    {
                        property var colors : ['red', 'green', 'blue']
                        property var widths : [100, 200, 300]
                        height: 100
                        width: widths[(verticalIndex + model.index) % widths.length]
                        color: colors[model.index % colors.length]

                        MouseArea {
                            anchors.fill: parent
                            onClicked: {
                                console.log("Rectangle.onClicked")
                            }

                        }
                    }

           }

    }

    //on top a Flickable
    Flickable {
       id: flickable
       height: parent.height
       width: parent.width
       contentHeight: 100*100 //nrOfRows * rowHeight
       contentWidth: 20*300 //nrOfEvent * max/averageEventWidth
     }


}

3 回答

  • 0

    我'm not giving you a perfect solution, but it'正在工作 . 当您在 ListView 的顶部使用 Flickable 时,您无法与其进行交互 . 所以,我已经 Flickable 使用 ListView 并且 contentXListViewcontentX ,但是这导致了一个循环并且我正在获得所需的行为 .

    QML Binding: Binding loop detected for property "value"
    

    EDIT

    所以,我没有使用 ListView 作为垂直列表,而是使用了 RepeaterColumn 并使用了属性绑定 . 它现在运作良好 .

    以下是更新版本 .

    import QtQuick 2.0
    
    Item {
        id: main
        visible: true
        width: 600
        height: 600
        property bool virticalFlick: false  //To get either vertical or horizontal flicking
    
        Flickable {
            anchors.fill: parent
            contentWidth: contentItem.childrenRect.width
            contentHeight: contentItem.childrenRect.height
            flickableDirection: Flickable.VerticalFlick
            interactive: (virticalFlick === true)?true:false
            Column {
                id: column
                spacing: 10
                Repeater {
                    id: repeater
                    model: 20
                    ListView {
                        id: horizontalList
                        width: 600;
                        height: 100;
                        clip: true
                        interactive: (virticalFlick === true)?false:true
                        spacing: 10
                        orientation: ListView.Horizontal
                        model: 20
                        property var verticalIndex : index
                        onMovingChanged: {
                            if(moving == true) {
                                for(var i=0; i<repeater.count ; i++) {
                                    /* If the property is later assigned a static value from a JavaScript statement,
                                this will remove the binding.
                                However if the intention is to create a new binding then the property
                                must be assigned a Qt.binding() value instead. This is done by passing a function to
                                Qt.binding() that returns the desired result */
                                    if (i !== index)
                                        repeater.itemAt(i).contentX = Qt.binding(function() { return contentX });
                                }
                            }
                            else {
                                for(var i=0; i<repeater.count ; i++) {
                                    if (i !== index)
                                        repeater.itemAt(i).contentX = contentX; // This will remove binding
                                }
                            }
    
                        }
    
                        delegate: Rectangle {
                            property var colors : ['red', 'green', 'blue']
                            property var widths : [100, 200, 300]
                            height: 100
                            width: widths[(ListView.view.verticalIndex + model.index) % widths.length]
                            color: colors[model.index % colors.length]
    
                            MouseArea {
                                anchors.fill: parent
                                onClicked: {
                                    console.log("Rectangle.onClicked")
                                }
    
                            }
                        }
                    }
                }
            }
        }
    }
    
  • 0

    以下确实有效,但最初的尝试似乎更优雅 .

    我仍需要在轻弹时比较性能(fps),尤其是在移动设备上 . 我也得到“绑定循环”警告,但我认为它们是误报 .

    import QtQuick 2.0
    
    Item {
    id: main
    visible: true
    width: 600
    height: 600
    
    ListView {
        id: verticalList
        width: parent.width;
        height: parent.height;
        anchors.fill: parent
        spacing: 10
        cacheBuffer: 500 // in pixels
        orientation: ListView.Vertical
        model: 100
        property var activeIndex : 0
        property var lastContentX : 0
        delegate:
            ListView {
                id: horizontalList
                width: parent.width;
                height: 100;
                spacing: 10
                cacheBuffer: 500 // in pixels
                orientation: ListView.Horizontal
                model: 20
                property var verticalIndex : index
                delegate:
                    Rectangle
                    {
                        property var colors : ['red', 'green', 'blue']
                        color: colors[model.index % colors.length]
    
                        height: 100
                        property var widths : [100, 200, 300]
                        width: widths[(verticalIndex + model.index ) % widths.length]
    
                        MouseArea {
                            z:10
                            anchors.fill: parent
                            onClicked: {
                                console.log("Rectangle.onClicked")
                            }
                            onPressed: {
                                console.log("Rectangle.onPressed")
                            }
                            onReleased: {
                                console.log("Rectangle.onReleased")
                            }
    
                        }
                    }
    
            onContentXChanged: {
                if(model.index === verticalList.activeIndex)
                {
                    verticalList.lastContentX = contentX
                }
            }
            onMovementStarted: {
                verticalList.activeIndex = model.index
                unbind();
            }
            onMovementEnded: {
                bind();
            }
    
            Component.onCompleted: {
                bind();
            }
    
            function bind()
            {
                contentX = Qt.binding(function() { return verticalList.lastContentX })
            }
            function unbind()
            {
                contentX = contentX ;
            }
           }
      }
    }
    
  • 0

    我最初的尝试需要进行以下修改

    • Flickable 限制为 flickableDirection : Flickable.HorizontalFlick 并删除 verticalList 上的 contentY : flickable.contentY

    • 通过这样做,没有垂直滚动了 . 这可以通过在 ListView 内移动 Flickable 来修复

    通过将以下 MouseArea 添加到 Flickable 收到

    • onClicked 事件

    例如 .

    MouseArea {
       anchors.fill: parent
       //see http://stackoverflow.com/questions/29236762/mousearea-inside-flickable-is-preventing-it-from-flicking
       onReleased: {
          if (!propagateComposedEvents) {
             propagateComposedEvents = true
          }
       }
    }
    

相关问题