Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Unsolved Can't get my ListView Scrollbehavior correct in my simple example

    QML and Qt Quick
    1
    2
    562
    Loading More Posts
    • 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.
    • L
      LowLevelM last edited by LowLevelM

      cross-posted from: https://stackoverflow.com/questions/57079018/qml-cant-get-my-listview-scrollbehavior-correct-in-my-simple-example

      Its my first time to use ListView and i need to implement a decent scroll behavior for my application
      it "works" but sometimes the animation behavior is a little bit strange

      I've wrote a small QML example (runnable with qmlscene tool) to show my problem

      alt text

      Sample source code:

      import QtQuick 2.2
      import QtQuick.Window 2.5
      
      Window {
          width: 500
          height: 700
          visible: true
      
          // my model ctrl is in C++
          // faked it here with pure QML to simplify the example
          ListModel {
              id: cppModel
              // different size - item type depdendend (just const here)
              ListElement { name: "Item 1"; active: false; height: 50 }
              ListElement { name: "Item 2"; active: false; height: 100 }
              ListElement { name: "Item 3"; active: false; height: 150 }
              ListElement { name: "Item 4"; active: false; height: 200 }
              ListElement { name: "Item 5"; active: false; height: 250 }
              ListElement { name: "Item 6"; active: false; height: 300 }
      
              property int currentItemIndex: -1
      
              function activate_item(index) {
                  // auto deactivate all others
                  for(var i = 0; i < rowCount(); i++) {
                      var active = (index === i)
                      get(i).active = active
                      if(active) {
                          currentItemIndex = i
                      }
                  }
              }
          }
      
          Component {
              id: listViewDelegate
      
              Rectangle
              {
                  height: model.active ? model.height : 30
                  width: 600
                  color: "transparent"
                  border {color: model.active ? "yellow" : "black"; width: 2}
      
                  Behavior on height {
                      NumberAnimation {
                          easing.type: Easing.InCirc
                          duration: 5000
                      }
                  }
      
                  Text {
                      text: model.name;
                      font.pixelSize: 24
                  }
      
                  MouseArea {
                      anchors.fill: parent
                      onClicked: {
                          cppModel.activate_item(model.index)
                      }
                  }
              }
          }
      
          Rectangle
          {
              width: 400
              height: 600
              border {color: "steelblue"; width: 2}
      
              ListView {
                  id: myList
                  anchors.fill: parent
                  clip: true
                  model: cppModel
                  delegate: listViewDelegate
      
                  header: Rectangle {
                      width: parent.width; height: 50
                      border {color: "red"; width: 2}
                      Text {
                          anchors.centerIn: parent
                          text: "Header"
                          font.pixelSize: 32
                      }
                  }
      
                  highlightMoveDuration: 5000
                  highlightMoveVelocity: -1
                  highlightResizeDuration: 5000
                  highlightResizeVelocity: -1
      
                  preferredHighlightBegin: 0
                  preferredHighlightEnd: currentItem.height
                  highlightRangeMode: ListView.StrictlyEnforceRange
      
                  snapMode: ListView.SnapToItem
      
                  currentIndex: -1
      
                  onMovementStarted: {
                      // show header again
                      highlightRangeMode = ListView.ApplyRange
                  }
                  onCurrentIndexChanged: {
                      // highlight current
                      highlightRangeMode = ListView.StrictlyEnforceRange
                  }
              }
      
              Connections {
                  target: cppModel
                  onCurrentItemIndexChanged: { // change comming from C++
                      if ( myList.currentIndex !== cppModel.currentItemIndex ) {
                          myList.currentIndex = cppModel.currentItemIndex
                      }
                  }
              }
          }
      }
      

      first: the item that is activated should be scrolled to top (that works) seems ok, only the animation i get are a little strange

      my 2 "bad" animation scenarios:

      if you activate Item 1..6 downwards, starting with Item 3 the Item Text is moved too far up and then comes back, the up scrolling should always stop at the items top, no bouncing etc. - i've already tried to replace the highlighter but gives me no better result

      if you open for example Item 6 and the scroll with mouse to Item 1 and activates item 1, the animation (seems to) first closes the Item 6 and then scrolls the list, better would be that the scrolling/and resize to the activated item 1 is prio and the closing animation of the former item does not block/stutter the item 1 animation

      would be glad if someone could kick me in the right direction how to solve the animation problems

      thanks

      1 Reply Last reply Reply Quote 0
      • L
        LowLevelM last edited by LowLevelM

        a played a while with the ListView options but can't get the animations right
        so i've tried to implement my own list view like item - as an example how the animation would feel

        working sample, with an fake c++ model, with the animations i want to see

        import QtQuick 2.5
        import QtQuick.Controls 2.5
        import QtQuick.Window 2.5
        
        Window {
            width: 500
            height: 700
            visible: true
        
            // my model ctrl is in C++
            // faked it here with pure QML to simplify the example
            ListModel {
                id: cppModel
                // different size - item type depdendend (just const here)
                ListElement { name: "Item 1"; active: false; height: 100 }
                ListElement { name: "Item 2"; active: false; height: 150 }
                ListElement { name: "Item 3"; active: false; height: 200 }
                ListElement { name: "Item 4"; active: false; height: 250 }
                ListElement { name: "Item 5"; active: false; height: 300 }
                ListElement { name: "Item 6"; active: false; height: 350 }
        
                property int currentItemIndex: -1
        
                function activate_item(index) {
                    // auto deactivate all others
                    for(var i = 0; i < rowCount(); i++) {
                        var active = (index === i)
                        get(i).active = active
                        if(active) {
                            currentItemIndex = i
                        }
                    }
                }
        
                function remove_item(index) {
                    if(currentItemIndex === -1) {
                        console.log("can remove not active item")
                        return
                    }
        
                    remove(currentItemIndex);
                }
        
                function deactivate_current_item()
                {
                    if(currentItemIndex === -1) {
                        console.log("can remove not active item")
                        return
                    }
                    get(currentItemIndex).active = false
                }
            }
        
            Column {
        
                Rectangle {
                    width: 320
                    height: 480
        
                    border { width: 2; color: "steelblue" }
        
                    Flickable {
                        id: flickable
                        clip: true
                        anchors.fill: parent
                        contentWidth: 320
                        contentHeight: 600
        
                        function goto_header()
                        {
                            contentY = 0
                        }
        
                        Behavior on contentY {
                            NumberAnimation {
                                easing.type: Easing.OutCubic
                                duration: 500
                            }
                        }
        
                        Rectangle {
                            id: myList
        
                            anchors.top: parent.top
                            anchors.left: parent.left
                            width: flickable.contentWidth
                            height: flickable.contentHeight
        
                            Column {
                                Rectangle {
                                    id: header
                                    width: 320
                                    height: 40
                                    color: "red"
                                    border { width: 2; color: "black" }
                                    Text { text: "Header"}
                                }
        
                                Repeater {
                                    model: cppModel
                                    Rectangle {
                                        readonly property int reducedSize: 30
                                        width: 320
                                        height: model.active ? model.height : reducedSize
                                        border { width: 2; color: "black" }
                                        Text {
                                            text: model.name
                                        }
        
                                        MouseArea {
                                            anchors.fill: parent
                                            onClicked: {
                                                // find new list contentY
                                                // works also if item above is shrinking
                                                // but only if shrinked height is for all items the same
                                                var newContentY = (model.index * reducedSize) + header.height
        
                                                cppModel.activate_item(model.index)
        
                                                // scroll to this element
                                                flickable.contentY = newContentY
                                            }
                                        }
        
                                        Behavior on height {
                                            NumberAnimation {
                                                easing.type: Easing.OutCubic
                                                duration: 500
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
        
                Rectangle {
                    height: 100
                    width: 320
        
                    Row
                    {
                        Button {
                            text: "Delete"
                            onClicked: {
                                console.log("Delete clicked")
                                cppModel.remove_item();
                                flickable.goto_header();
                            }
                        }
                        Button {
                            text: "Save"
                            onClicked: {
                                console.log("Save clicked")
                                cppModel.deactivate_current_item()
                            }
                        }
                    }
                }
            }
        }
        
        

        Screenshot of the sample program

        0_1563517642889_Screenshot from 2019-07-19 08-27-03.png

        1 Reply Last reply Reply Quote 0
        • First post
          Last post