English | Български

Manual ListView Item Positioning

Introduction

Let’s say for instance instead of wanting a plain ListView with its items laid out horizontally and linearly, you instead want a list to respond so that when one item is selected, that item animates towards a different position (lower y value). This item is singled out and when a different item is selected, they swap places. This was useful for my case of KDE’s login manager theme, where the items were user face images.

Implementation

Here we create a ListView, a simple array just as filler for what your model will actually be, a delegate with an image and text item, and then we manually set the y and x position of them.

QML Code

  1. import QtQuick 1.0
  2.  
  3. Item {
  4.     width: 600
  5.     height: 600
  6.     property int itemWidth: 50
  7.  
  8.  
  9.     ListView {
  10.         id: view
  11.         model: new Array(1,2,3,4,5,6,7,8)
  12.         delegate: item
  13.         anchors {
  14.             top: parent.top;
  15.             topMargin: 10;
  16.             horizontalCenter:
  17.             parent.horizontalCenter;
  18.             bottom:
  19.             parent.bottom;
  20.         }
  21.         width: model.length * itemWidth + (model.length - 1) * spacing
  22.         spacing: 2
  23.         orientation: Qt.Horizontal
  24.         snapMode: ListView.SnapOneItem
  25.         highlightRangeMode: ListView.ApplyRange
  26.         interactive: false
  27.         Component.onCompleted: currentIndex = -1;
  28.     }
  29.  
  30.  
  31.     Component {
  32.         id: item
  33.  
  34.         Rectangle {
  35.             width: itemWidth
  36.             height: 50
  37.             color: "red"
  38.             x: {
  39.                 if (ListView.isCurrentItem) {
  40.                     if (view.flickingHorizontally) {
  41.                         (view.width/2) - (width/2)
  42.                     } else {
  43.                         (view.width/2)-(width/2)
  44.                     }
  45.                 } else {
  46.                     if ( view.currentIndex==-1) {
  47.                         index * (width + view.spacing)
  48.                     } else {
  49.                         if ( index < view.currentIndex) {
  50.                             index * (width + view.spacing) + (width/2)
  51.                         } else {
  52.                             index * (width + view.spacing) - (width/2)
  53.                         }
  54.                     }
  55.                 }
  56.             }
  57.             y: ListView.isCurrentItem ? 200 : 0
  58.             Behavior on x { SpringAnimation { spring: 4; damping: 0.4 } }
  59.             Behavior on y { SpringAnimation { spring: 4; damping: 0.4 } }
  60.  
  61.             Text {
  62.                 text: model.index
  63.             }
  64.  
  65.             MouseArea {
  66.                 anchors.fill: parent
  67.                 onClicked: {
  68.                     if (!ListView.isCurrentItem)
  69.                         view.currentIndex = index;
  70.                     else
  71.                         view.currentIndex = -1;
  72.                 }
  73.             }
  74.         }
  75.     }
  76. }

Results

!https://lh4.googleusercontent.com/-DOTQe7zsIBg/Tj3MjY6plMI/AAAAAAAAAUw/3uAoYO33h3E/s800/qml list animation example.png!

Possible Issues

I’ve encountered some issues with this approach, however. It looks like there is a bug in the ListView which screws with the X value of a delegate item if the model’s data is changed. I’m not sure if this is just me, or if there’s an easy way to fix it…

Categories:

  • HowTo
  • snippets
  •