QML:同时滚动多个ListView

3
我希望有一个单一(垂直)ListView,并使用(水平)ListView委托。水平委托应该同步滚动。为此,我在ListViews上方放置了一个Flickable,并将水平ListView的contentX绑定到Flickable的contentX(并且垂直ListView的contentY也是如此)(注意:这里描述了不同的方法来同步ListView滚动,但这似乎在移动设备上存在性能问题)
下面的代码基本上可以工作,但仍然存在以下问题:
  • 我无法在矩形中获得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
     }


}
3个回答

0

我不能给你一个完美的解决方案,但它是有效的。当你在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")
                            }

                        }
                    }
                }
            }
        }
    }
}

感谢您的输入。水平滑动确实不够流畅(立即停止),很可能是由于绑定循环引起的。但我可能会根据这个版本进行更多的实验。 - Marc Van Daele
再次感谢!现在滑动确实很流畅。然而,我真的需要一个ListView而不是Repeater(因为Repeater使用更多的内存并且在可见窗口外绘制,可以在设置QSG_VISUALIZE=overdraw时看到)。此外,我需要垂直和水平滚动(但没有对角线滚动,这是我最初尝试时遇到的问题)。我的答案符合这些要求,但我仍然需要比较两个选项的性能。 - Marc Van Daele

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

其中有很多绑定循环。我认为这将导致一些重大的性能问题。 - Vedanshu

0

我需要对我的初始尝试进行以下修改:

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

  • 这样做后,就不再有垂直滚动。可以通过将Flickable移动到ListView内来解决此问题。

  • 通过将以下MouseArea添加到Flickable中,可以接收到onClicked事件

例如:

MouseArea {
   anchors.fill: parent
   //see https://dev59.com/MInca4cB1Zd3GeqP5QlR
   onReleased: {
      if (!propagateComposedEvents) {
         propagateComposedEvents = true
      }
   }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接