QML: scroll multiple ListViews synchronously

时间:2015-11-12 12:09:11

标签: qt listview mouseevent qml

I want to have a single (vertical) ListView with (horizontal) ListView delegates.

The horizontal delegates should scroll synchronously. To do so, I put a Flickable on top of the ListViews and bind the contentX of the horizontal ListView to the contentX of the Flickable (and the same for the contentY of the vertical ListView) (Note: Here a different approach was described for the synchronous ListView scrolling but this seems to have performance issues on mobile devices)

The code below kind of works but still has the following issues

  • I don't get the onClicked in the Rectangle (I do get it when I remove the top Flickable)
  • I want either horizontal flicking or vertical flicking but not both at the same time. I can restrict the flicking of the top Flickable by setting flickableDirection: Flickable.HorizontalFlick but then I can't flick vertically anymore (I was hoping that the Flickable would pass on unused mouse events to the vertical ListView but this doesn't seem to happen)

Suggestions on how to fix these issues?

Any help appreciated!

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 :(得分:0)

我没有给你一个完美的解决方案,但它正在发挥作用。当您在Flickable顶部使用ListView时,您无法与之互动。所以,我在Flickable后面ListView使用了contentXFlickable的{​​{1}},但这导致了一个循环而我&# 39;得到以下输出,但我们得到了所需的行为。

ListView

修改

因此,我没有使用QML Binding: Binding loop detected for property "value" 作为垂直列表,而是使用了ListViewRepeater并使用了属性绑定。它现在运作良好。

以下是更新版本。

Column

答案 1 :(得分: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 ;
        }
       }
  }
}

答案 2 :(得分:0)

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

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

  • 通过这样做,不再有垂直滚动。可以通过移动Flickable

  • 中的ListView来解决此问题 通过将以下onClicked添加到MouseArea

    收到
  • Flickable个事件

例如

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