【问题标题】:QML: scroll multiple ListViews synchronouslyQML:同步滚动多个ListView
【发布时间】:2015-11-12 12:09:10
【问题描述】:

我想要一个带有(水平)ListView 代表的(垂直)ListView。

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

下面的代码可以工作,但仍然存在以下问题

  • 我没有在 Rectangle 中看到 onClicked(当我删除顶部的 Flickable 时我确实看到了)
  • 我想要水平滑动或垂直滑动,但不能同时使用两者。我可以通过设置flickableDirection: Flickable.HorizontalFlick 来限制顶部 Flickable 的轻弹,但是我不能再垂直轻弹(我希望 Flickable 会将未使用的鼠标事件传递给垂直 ListView,但这似乎不会发生)

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

任何帮助表示赞赏!

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
     }


}

【问题讨论】:

    标签: qt listview mouseevent qml


    【解决方案1】:

    我没有给你一个完美的解决方案,但它确实有效。当您在ListView 的顶部使用Flickable 时,您无法与之交互。因此,我在ListView 下方使用了Flickable,并限制了FlickableListViewcontentX,但这会导致循环,我得到以下输出,但我们得到了期望的行为。

    QML Binding: Binding loop detected for property "value" 
    

    编辑

    所以,我没有使用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")
                                }
    
                            }
                        }
                    }
                }
            }
        }
    }
    

    【讨论】:

    • 感谢您的意见。水平轻弹确实不平滑(立即停止),很可能是由于绑定循环。但我可能会在这个版本的基础上做更多的实验。
    • 再次感谢!现在弹幕确实很流畅。但是,我真的需要一个 ListView 和一个中继器(因为中继器使用更多内存并在可见窗口之外绘制,如设置 QSG_VISUALIZE=overdraw 时所见)。此外,我需要垂直和水平滚动(但没有我最初尝试的对角滚动)。我的答案符合这些要求,但我仍然需要比较两个选项的性能。
    【解决方案2】:

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

    我仍然需要比较轻弹时的性能 (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 ;
            }
           }
      }
    }
    

    【讨论】:

    • 里面有很多绑定循环。我认为这会导致一些主要的性能问题。
    【解决方案3】:

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

    • 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
          }
       }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-20
      • 1970-01-01
      相关资源
      最近更新 更多