ListView kinetic scrolling speed
-
Hello,
after I spent many hours with investigating my problem, I need to ask for a help. I have no idea what else could I try to identify and fix it.
Let's describe what's happening. I wrote a music player with a library and a playlist. If I run it on a desktop, everything works as expected. But on Android the kinetic scrolling doesn't work correctly. If I hold finger on the touchscreen and move the playlist up and down, it moves very smooth and fast. Just like expected. But as soon as I release my finger, the scrolling slows down rapidly. So I can not scroll the ListView fast, which is really needed with long playlists.
I thought that maybe my delegate is to complicated, so I simplified it only to a rectangle and a text. But it didn't help. I tried to use a different model with only numbers instead of my C++ QAbstractListModel. But that didn't help neither.
Exactly the same problem is also in the library browser which uses different delegate and model. So it must be somewhere else in the application. But where could it be?
The complete code can be found here. Do you have any idea what could be the problem and what could I do to identify it?
This is the playlist item delegate although I don't think the problem is here:
import QtQuick 2.6 FocusScope { id: playlistItem property string pl_title property string pl_artist property string pl_album property string pl_queue property int itemHeight: config.libraryFontSize*2 property bool selected: false anchors.right: parent ? parent.right : playlistDelegate.right anchors.left: parent ? parent.left : playlistDelegate.left height: itemHeight Keys.onReturnPressed: { controller.playTrack(index); } Keys.onSpacePressed: { if (config.playbackState == "playing") controller.buttonPressed("pause"); else if (config.playbackState == "paused") controller.buttonPressed("play"); else controller.playTrack(index); } Timer { id: resizeTimer interval: 5000 repeat: false onTriggered: { index == playlistView.currentIndex ? playlistItem.state = 'Current' : playlistItem.state = 'State0'; playlistItem.selected = false; playlist.contentYOffset -= config.libraryFontSize*2; } } Timer { id: scrollTimer interval: 200 repeat: false property int selectIndex onTriggered: { playlistView.highlightFollowsCurrentItem = true; playlistView.currentIndex = selectIndex; } } Rectangle { id: frame anchors.fill: parent anchors.topMargin: units.dp(2) anchors.bottomMargin: units.dp(2) color: "#00000000" radius: itemHeight/4 border.width: units.dp(2) border.color: main.borderColor MouseArea { id: itemMouseArea anchors.fill: parent anchors.rightMargin: 0 onClicked: { if (!playlist.itemMoving) { playlistTab.focus = true; if (playlistItem.state == 'Selected') { resizeTimer.stop(); playlistView.currentIndex = index; playlistItem.state = 'Current'; playlist.contentYOffset -= config.libraryFontSize*2; playlistItem.selected = false; } else { playlistView.currentIndex = -1; var center = playlistView.indexAt(10, playlistView.height/2+playlistView.contentY); playlistView.currentIndex = center; playlistView.currentIndex = index; playlistItem.state = 'Selected'; playlist.contentYOffset += config.libraryFontSize*2; playlistItem.selected = true; resizeTimer.restart(); } controller.playlistSelectionChanged(index); } } } Text { id: queueText height: itemHeight/5 color: main.selectionColor text: pl_queue anchors.left: parent.left anchors.top: parent.top anchors.leftMargin: playlistItem.queue == '' ? 0 : 10 anchors.topMargin: units.dp(5) smooth: true font.pixelSize: config.smallFontSize } Text { id: titleText height: itemHeight/3 color: main.textColor text: pl_artist == '' ? pl_title : pl_title+' - ' anchors.left: queueText.right anchors.top: parent.top anchors.rightMargin: units.dp(5) anchors.leftMargin: units.gu(1) anchors.topMargin: itemHeight/2 - itemHeight/6 - units.dp(2) width: parent.width-dummyTitleText.queueWidth-units.gu(2) clip: false style: Text.Normal wrapMode: Text.NoWrap elide: Text.ElideRight smooth: true verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignLeft font.pixelSize: config.libraryFontSize focus: true } Text { id: dummyTitleText property int queueWidth: playlistItem.queue == '' ? 0 : queueText.width+10 visible: false color: "#00000000" text: pl_artist == '' ? pl_title : pl_title+' - ' style: Text.Normal wrapMode: Text.NoWrap font.pixelSize: config.libraryFontSize } Text { property int leftMargin: dummyTitleText.width+dummyTitleText.queueWidth+units.gu(1) id: artistText height: itemHeight/3 color: main.textColor text: pl_artist anchors.leftMargin: leftMargin width: parent.width-leftMargin-units.gu(2) elide: Text.ElideRight anchors.top: parent.top font.pixelSize: config.libraryFontSize verticalAlignment: Text.AlignVCenter wrapMode: Text.NoWrap horizontalAlignment: Text.AlignLeft anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter style: Text.Normal smooth: true } Text { id: albumText opacity: 0 height: itemHeight/3 color: main.textColor text: pl_album anchors.leftMargin: units.gu(2) width: parent.width-2*itemHeight-units.gu(1) elide: Text.ElideRight anchors.bottom: parent.bottom font.pixelSize: config.normalFontSize verticalAlignment: Text.AlignVCenter clip: false wrapMode: Text.NoWrap horizontalAlignment: Text.AlignLeft anchors.left: parent.left style: Text.Normal smooth: true anchors.bottomMargin: itemHeight/8 } Item { id: buttons property int buttonSize: itemHeight-units.gu(2) width: parent.height height: parent.height-units.gu(2) anchors.rightMargin: units.gu(1) opacity: 0 visible: false anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right MyButton { id: upButton iconSource: "images/up.svg" width: buttons.buttonSize height: buttons.buttonSize anchors.top: parent.top anchors.left: parent.left anchors.leftMargin: units.gu(1) visible: index == 0 ? false : true onClicked: { controller.movePlaylistItem(index,false); playlistItem.state = 'Selected'; resizeTimer.restart(); playlist.itemMoving = true; playlist.restartMovingTimer(); if (playlistView.count*itemHeight+playlist.contentYOffset > playlistView.height) { if (playlistView.contentY > itemHeight) playlistView.contentY -= itemHeight; else playlistView.contentY = 0; } } } MyButton { id: downButton iconSource: "images/down.svg" width: buttons.buttonSize height: buttons.buttonSize anchors.bottom: parent.bottom anchors.left: parent.left anchors.leftMargin: units.gu(1) visible: index == playlistView.count-1 ? false : true onClicked: { controller.movePlaylistItem(index,true) playlistItem.state = 'Selected' resizeTimer.restart() playlist.itemMoving = true; playlist.restartMovingTimer(); playlistView.height, playlistView.count, itemHeight); if (playlistView.count*itemHeight+playlist.contentYOffset > playlistView.height) { if (playlistView.contentY < playlistView.count*itemHeight-playlistView.height+playlist.contentYOffset) { playlistView.contentY += itemHeight; } else { playlistView.contentY = playlistView.count*itemHeight-playlistView.height+playlist.contentYOffset; } } } } MyButton { id: delButton width: buttons.buttonSize height: buttons.buttonSize iconSource: "images/delete.svg" anchors.bottom: parent.bottom anchors.rightMargin: units.gu(1) anchors.right: parent.right onClicked: { playlist.updateIndex(-1); playlistItem.state = 'Deleting'; playlist.contentYOffset -= config.libraryFontSize*2; controller.removeFromPlaylist(index); } } MyButton { id: queueButton iconSource: playlist.queueActive ? "" : "images/queue.svg" width: buttons.buttonSize height: buttons.buttonSize anchors.top: parent.top anchors.rightMargin: units.gu(1) anchors.right: parent.right onClicked: { if (!playlist.queueActive) controller.addToQueue(index) } } } } states: [ State { name: "Current" when: playlistItem.ListView.isCurrentItem && !playlistItem.selected PropertyChanges { target: frame; border.color: main.selectionColor } PropertyChanges { target: titleText; color: main.selectionColor } PropertyChanges { target: artistText; color: main.selectionColor } PropertyChanges { target: albumText; color: "#00000000" } }, State { name: "Selected" PropertyChanges { target: frame; border.color: playlistItem.ListView.isCurrentItem ? main.selectionColor : main.textColor } PropertyChanges { target: playlistItem; height: config.libraryFontSize*4 } PropertyChanges { target: buttons; opacity: 1; visible: true } PropertyChanges { target: itemMouseArea; anchors.rightMargin: itemHeight } PropertyChanges { target: titleText; color: playlistItem.ListView.isCurrentItem ? main.selectionColor : main.textColor; anchors.topMargin: itemHeight/8+units.gu(2); text: pl_title; width: parent.width-2*itemHeight-dummyTitleText.queueWidth-units.gu(1) } PropertyChanges { target: artistText; color: playlistItem.ListView.isCurrentItem ? main.selectionColor : main.textColor; width: parent.width-2*itemHeight-units.gu(1); anchors.leftMargin: 10; } PropertyChanges { target: albumText color: playlistItem.ListView.isCurrentItem ? main.selectionColor : main.textColor; anchors.bottomMargin: itemHeight/8+units.gu(2) opacity: 1 } }, State { name: "Deleting" PropertyChanges { target: frame; border.color: "#00000000" } PropertyChanges { target: playlistItem; height: config.libraryFontSize*4 } PropertyChanges { target: buttons opacity: 0 visible: false } PropertyChanges { target: artistText opacity: 0 } PropertyChanges { target: albumText opacity: 0 } PropertyChanges { target: titleText opacity: 0 } } ] transitions: [ Transition { from: "*"; to: "*" NumberAnimation { properties: "height"; easing.type: Easing.Linear; duration: 200 } NumberAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: 200 } NumberAnimation { properties: "anchors.topMargin"; easing.type: Easing.Linear; duration: 200 } NumberAnimation { properties: "anchors.leftMargin"; easing.type: Easing.Linear; duration: 200 } ColorAnimation { duration: 200 } } ] }