【问题标题】:How to stop ListView for "jumping" when model is changed更改模型时如何停止ListView“跳跃”
【发布时间】:2015-09-11 16:07:56
【问题描述】:

我需要做什么:我需要在 QML 中使用 ListView 创建一个 聊天窗口 来存储聊天消息。我设置了listView.positionViewAtEnd() 以便跟踪最后的消息。当我向上滚动时,我禁用positionViewAtEnd,这样我每次收到新消息时都可以阅读过去的消息而不会跳到最后。

问题:向上滚动后,每次收到新消息时,它都会在列表开头跳转。为了解决这个问题,我设法存储列表的 contentY 并在每次调用 onCountChanged 处理程序时重置它(参见下面的代码):

ListView {
    id: messagesList
    model: contact? contact.messages: []
    delegate: delegate
    anchors.fill: parent
    anchors.bottomMargin: 20
    height: parent.height
    anchors.margins: 10

    property int currentContentY

    onMovementEnded: {
       currentContentY = contentY
    }

    onCountChanged: {
        contentY = currentContentY
    }
    onContentYChanged: {
        console.log(".....contentY: " + contentY)
    }
}   

问题是,即使我设置了最后一个contentY,在模型更改之前,列表仍然会跳动一点几个像素,而不是在结尾或开头)并且它并不总是跳跃。当我转到列表顶部并打印 contentY 我得到负值。理论上,列表开头的contentY应该是0

谁能告诉我出了什么问题?或者也许建议另一种解决方案来创建我的消息列表?

比你提前! :)

【问题讨论】:

  • 你如何填充/修改contact.messages
  • 这是一个使用 qqmllistproperty 从 c++ 公开的列表。当它从 c++ 修改时(添加消息后)我发出一个信号,来自 qml 的列表视图知道更新它的模型
  • MovementEnded 处理程序是否一直被调用?从未使用QQmlListProperty 作为模型,但它似乎可以工作quite fine。无论如何,QAbstractListModel 的子类可以完美地完成这里的工作。
  • QAbstractItemModel 或任何子类都可以。由于ListView 确实使用QAbstractListModel 显示列表更好。至少如果您不必在树结构中移动。这似乎不是你的情况。
  • 感谢@BaCaRoZzo 的建议。我使用了 QAbstractListModel,现在它可以工作了。

标签: qt listview model qml qtquick2


【解决方案1】:

一种可能的解决方案是将 ListView 插入 Flickable 并禁用 ListView 的 interactive 标志

    Flickable {
        id: fparent
        anchors.fill: parent
        anchors.bottomMargin: 20
        anchors.margins: 10

        interactive: true
        clip: true
        flickableDirection: Flickable.VerticalFlick
        contentHeight: messagesList.height

        ListView {
            id: messagesList
            width: parent.width
            height: childrenRect.height
            clip: true
            model: contact? contact.messages: []
            delegate: delegate
            interactive: false
            onCountChanged: {
                fparents.returnToBounds();
            }
        }
    }

【讨论】:

    【解决方案2】:

    为什么不使用 onCountChanged 槽来设置 ListView 最后?

    onCountChanged: {
       messagesList.positionViewAtEnd()
    }
    

    【讨论】:

    • 我用过,但如果我不在末尾时收到任何新消息,我不想跳到末尾(当我在列表中间时向上滚动)
    • 在这种情况下,您可以根据某个事件禁用 positionViewAtEnd() 并在另一个事件上启用它。我觉得你的要求很矛盾。
    • 这不是答案。为什么我的问题是矛盾的?以Skype为例。我想做一些类似的东西。 positionViewAtEnd 仅在我位于列表底部时才解决问题! I 当我位于列表的中间时,我不想跳到最后,我想留在那里。
    • 您可以使用 onMovementStarted 插槽禁用 positionViewAtEnd(),然后在 onMovementEnded 中激活它以启用它。如果您停在中间不确定要在那里停留多长时间,也许您也可以使用计时器,一旦运动结束等待几秒钟,然后再启用 positionViewAtEnd()。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-07
    • 2022-11-14
    • 2016-09-14
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多