Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. How to know when ListView item enters the visible area?

How to know when ListView item enters the visible area?

Scheduled Pinned Locked Moved QML and Qt Quick
6 Posts 4 Posters 8.8k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • E Offline
    E Offline
    Etchelon
    wrote on last edited by
    #1

    Hi,

    I'm looking for a way to know when an item in my ListViews enters the visible area, so that after a certain delay I can mark that item as read. I can't find any signal, and knowing that ListView preloads some items when they are about to be shown makes things even harder. I think this is a common problem, because in nearly all social apps you need to know when a notification/message is read by the user...

    Thanks in advance!

    1 Reply Last reply
    0
    • GianlucaG Offline
      GianlucaG Offline
      Gianluca
      wrote on last edited by
      #2

      I use different techniques:

      If the ListView shows only one item in the screen than I set highlightRangeMode to ListView.StrictlyEnforceRange and in this way the currentItem is always set to the only item on the screen and via onCurrentIndexChanged it's possible to track which item is on the screen

      If the ListView shows more than one item in the screen than I use contentX (or contentY) for calculate which items are currently displayed on the screen. You don't have a signal that tell you which items are visible, so you have to calculate in some ways. Probably there is some alternative, but with ListView I found easy to use contentX (or contentY).

      Another alternative, (but, I never used), If the ListView shows more that one item but you just need to track one a time, you can set preferredHighlightBegin and preferredHighlightEnd to a range where typically you can suppose that the user has more attention on the item and setting hightlightRangeMode to ListView.ApplyRange then the currentIndex always follow the scrolling and you can use onCurrentIndexChanged

      I 1 Reply Last reply
      2
      • J Offline
        J Offline
        Jens
        wrote on last edited by
        #3

        I agree with Cianlucas suggestions. ListView will not actually preload items by default unless you ask for it and you can explicitly set the cacheBuffer to 0 to prevent that. So for most cases you can still rely on the create/destroy signals for your delegates though an item might be just outside of the visible area. In my own app I collapsed messages by default, forcing the user to expand message content as in an e-mail client, but that would be too inconvenient for most messaging apps.

        Here is a simple example that shows how you can track randomly sied items beeing completely visible in view:

        @
        import QtQuick 2.3
        import QtQuick.Controls 1.2

        ApplicationWindow {
        visible: true
        width: 640
        height: 480

        ListView {
            id: list
            anchors.fill: parent
            model: 1000
            cacheBuffer:1000
            delegate: Rectangle {
                id: dg
                property int yoff: Math.round(dg.y - list.contentY)
                property bool isFullyVisible: (yoff > list.y && yoff + height < list.y + list.height)
                border.color: Qt.darker(color, 1.2)
                color: isFullyVisible ? "#ccffcc" : "#fff"
                height: Math.random() * 200
                width: parent.width
                Text {text: "Fully visible:" + isFullyVisible  ; anchors.centerIn: parent}
            }
        }
        

        }

        @

        1 Reply Last reply
        1
        • E Offline
          E Offline
          Etchelon
          wrote on last edited by
          #4

          Thank you guys, it works wonders!
          Jens, your code is perfect, I just had to realize that list.y in my case is relative to its parent while the item's y is relative to the list, so in your case list.y and the first element's y are both 0 and there are no problems; in my code I had list.y = 44 and the delegate's y was 0, so I just removed list.y from the equation! And added equality to the comparison operators to include the first (and last) items :D

          Still, I wonder why such a simple signal isn't emitted... I mean, from what I understand every visual object goes through a painting() event when it becomes visible, so why not just bubble that signal up to QML?

          Thanks again!

          1 Reply Last reply
          0
          • J Offline
            J Offline
            Jens
            wrote on last edited by
            #5

            Etchelon: It's not as simple as you might think. When using hardware accelleration as we do in Qt 5, you don't always know if a rendered Item is actually visible to the user without some overhead. That said, ListView in particular can easily find out if an item is visible as evidenced by the example above. Given the fairly easy workaround, I am not sure if it is worth adding extra signals and performance overhead in order to make the API more convenient but it's certainly possible.

            1 Reply Last reply
            0
            • GianlucaG Gianluca

              I use different techniques:

              If the ListView shows only one item in the screen than I set highlightRangeMode to ListView.StrictlyEnforceRange and in this way the currentItem is always set to the only item on the screen and via onCurrentIndexChanged it's possible to track which item is on the screen

              If the ListView shows more than one item in the screen than I use contentX (or contentY) for calculate which items are currently displayed on the screen. You don't have a signal that tell you which items are visible, so you have to calculate in some ways. Probably there is some alternative, but with ListView I found easy to use contentX (or contentY).

              Another alternative, (but, I never used), If the ListView shows more that one item but you just need to track one a time, you can set preferredHighlightBegin and preferredHighlightEnd to a range where typically you can suppose that the user has more attention on the item and setting hightlightRangeMode to ListView.ApplyRange then the currentIndex always follow the scrolling and you can use onCurrentIndexChanged

              I Offline
              I Offline
              Ilnur
              wrote on last edited by
              #6

              @Gianluca Your advice was helpful for me! Thank you for solution)

              1 Reply Last reply
              0

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved