【问题标题】:QML: prevent ListView from returning at beginning on model changeQML:防止 ListView 在模型更改开始时返回
【发布时间】:2021-12-02 14:50:41
【问题描述】:

当我尝试通过ListView 显示数据时,每次更新模型时,视图都会返回到开头。
有没有办法让ListView 处理模型更新而不更改内部FlickablevisibleArea(或以合理的方式更改它)?
理想情况下,同一区域应保持可见。

这是一个您可以看到该行为的最小示例:如果您在flickable(左侧)和listView(右侧)中向下滚动,当计时器被触发时,第一个计时器将停留在您所在的位置离开它,第二个会回到开头。
QML online live example

import QtQuick 2.15

Rectangle {
    id:root

    property int model: 10
    property int delegateHeight: height/10*0.8
    property int delegateSpacing: height/10*0.2

    color: "#afafaf"
    anchors.fill: parent

    Timer {
        interval: 5000
        repeat: true
        running: true

        onTriggered: root.model++
    }

    Flickable {
        id: flickable

        x: 0
        y: 0
        width: parent.width/2
        height: parent.height
        clip: true
        contentHeight: root.delegateHeight*repeater.count

        Repeater {
            id: repeater

            model: root.model

            delegate: Rectangle {
                x: 0
                y: (root.delegateHeight+root.delegateSpacing)*index
                width: flickable.width
                height: root.delegateHeight
                color: "#abcdef"

                Text {
                    text: index+1
                }
            }
        }
    }

    ListView {
        id: listView

        x: parent.width/2
        y: 0
        width: parent.width/2
        height: parent.height
        clip: true
        model: root.model
        spacing: root.delegateSpacing

        delegate: Rectangle {
            width: ListView.view.width
            height: root.delegateHeight
            color: "#fedcba"

            Text {
                text: index+1
            }
        }
    }
}

编辑:我找到了一种解决方法,但我认为这不是正确的方法。
像这样添加到listView 会保持visibleArea 在模型上的位置增加,但在减少计数器时可能会有一些缺点。

        property real lastY: 0

        onContentYChanged: {
            if(!moving){
                listView.contentY = listView.lastY+listView.originY
            }
            listView.lastY = listView.contentY-listView.originY
        }

【问题讨论】:

  • 您为什么不认为您的解决方法是正确的方法?
  • 我认为,如果在视图显示内容区域的底部时,内容会缩小,就像在上面的示例中降低模型数量一样,它可能会出现异常。可能我在计算新内容位置时必须考虑内容的大小。明天我会尝试证明我的观点。
  • 您可能需要为这种情况做一些额外的事情,但我根本不认为这是一种解决方法。我认为这可能是实现您想要的唯一方法。当模型发生变化时,ListView 不知道你想看到新数据的哪一部分,所以你必须手动滚动它,这似乎是你在做的事情。

标签: listview qml qt5 qtquick2


【解决方案1】:

我已经调整了提出的解决方法来处理收缩情况。

基本上,每次用户移动内容时,组件都会存储新的位置。
当内容自行移动时,例如模型发生变化,组件会恢复用户最后设置的位置,避免将其置于视图之外。

要实现这种行为,应该将类似这样的内容添加到ListView

        property real lastY: 0

        onContentYChanged: {
            if (!moving) {
                listView.contentY = Math.max(0, Math.min(listView.lastY, listView.contentHeight-listView.height))+listView.originY
            }
            listView.lastY = listView.contentY-listView.originY
        }

工作审查示例here

可能还有一些改进的空间,但目前这种机制满足我的需求。

【讨论】:

    猜你喜欢
    • 2011-02-28
    • 1970-01-01
    • 1970-01-01
    • 2015-09-11
    • 1970-01-01
    • 2021-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多