Hi,
I use an AppListView with a C++ Model. Everything is working as expected, except the restoreScrollPosition(). I store the last scroll position before updating the model with:
rootTP.timelinePos = listView.getScrollPosition();
// debug output
qml: store pos
qml: {"index":10,"pos":{"x":0,"y":228.0000198694679}}
After the model changed I send a signal in my c++ backend, onModelChanged() to restore the position:
listView.restoreScrollPosition(timelinePos);
// debug output
qml: restore pos
qml: {"index":10,"pos":{"x":0,"y":228.0000198694679}}
So I am absolutely sure that the position information is not overwritten during the model change.
But it does not work. Then I tried to add a custom button which restores the scroll position on click, to be sure that it has nothing to do with timing or signal problems, but it does not work either.
Has somebody a hint or maybe a solution? 🙂
Here is my Page.qml (I stripped code for better overview):
import Felgo 3.0
import QtQuick 2.0
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.3
import Felgo 3.0
import "../R24"
import "../util"
import ruhr24.backend 1.0
Page {
id: rootTP
property var timelinePos
Dialog {
// [...]
}
// The c++ backend
Backend {
id: backend
language: Qt.locale().name.substring(0, 2) || "de"
onErrorMessage: {
messageDialog.title = errorString;
messageDialog.open();
}
// THIS GETS FIRED WHEN BACKEND LOADING IS STARTED OR STOPPED
// PARAMETER bool status
onIsLoadingChanged: {
if(status){
rootTP.timelinePos = listView.getScrollPosition();
console.log("store pos");
console.log(JSON.stringify(rootTP.timelinePos));
// play loading animation
customBar.play();
} else {
// stop loading animation
customBar.stop();
}
}
onConfigChanged: {
// if there is a banner, set it up
rootTP.setBanner();
// reload menu
rootTP.setMenu();
}
// THIS GETS FIRED WHEN THE MODEL CHANGED
onModelChanged: {
listView.restoreScrollPosition(timelinePos);
console.log("restore");
console.log(JSON.stringify(rootTP.timelinePos));
// update emojis
var modelLen = getTimelineModel().length || 0;
for(var i2 = 0; i2 < modelLen; i2++){
var _set = database.getValue( getTimelineModel()[i2].post_id );
if( typeof _set !== 'undefined' && typeof _set.id !== 'undefined' ){
getTimelineModel()[i2].post_most_reactions = _set.reactions;
getTimelineModel()[i2].post_total_reactions = _set.total;
}
}
}
}
PageNavBarBackground {
id: customBar
onLogoClick: {
// this works
listView.positionViewAtBeginning();
}
}
// left menu, language switch, categories etc
AppDrawer {
// [...]
} // - end AppDrawer
// Main Navigation Drawer Button
leftBarItem: IconButtonBarItem {
// [...]
}
// HERE I TRIED TO HANDLE THE SCROLL POSITION MANUALLY
rightBarItem: IconButtonBarItem {
icon: IconType.refresh
onClicked: {
backend.nextPage()
listView.restoreScrollPosition(timelinePos)
}
}
// One Signal Push Notifications
OneSignal {
// [...]
}
AdMobBanner {
// [...]
}
// store data between states,
// but clear everything at restart
Storage {
// [...]
}
// HERE IS THE LISTVIEW
AppListView {
id: listView
anchors.top: customBar.bottom
anchors.bottom: parent.bottom
model: backend.model
delegate: ArticleRow {
id: timelineRow
onSelected: {
navigationStack.push(articlePageComponent, {
post_url: backend.filterUrl( timelineRow.post_external_url, timelineRow.post_url )
})
}
onEmojiUpdate: { // onEmojiUpdate(int post_id, int total, var most_reactions)
// store the emoji state into temporary database
var _obj = {id: post_id, total: total, reactions: most_reactions};
database.setValue(_obj.id, _obj)
}
}
backgroundColor: "#000000"
scrollIndicatorVisible: false
// Load newer elements by pulling the list down
PullToRefreshHandler {
id: refreshHandler
contentColor: Theme.navigationBar.titleColor
onRefresh: {
backend.firstPage();
}
} // - end PullToRefreshHandler
// Load more elements if this item becomes visible
// footer: VisibilityRefreshHandler {
// id: footerRefreshHandler
// onRefresh: {
// backend.nextPage();
// }
// } // - end VisibilityRefreshHandler
Component.onCompleted: {
// init backend and fetch configuration from api
backend.init();
// init model
backend.firstPage();
}
} // - AppListView end
// get config object
function getConfig(){
return (typeof backend.config !== 'undefined' ? backend.config : ({}) );
}
// get the timeline model
function getTimelineModel(){
return (typeof backend.model !== 'undefined' ? backend.model : []);
}
// get the timeline language
function getLanguage(){
return backend.language;
}
// set the timeline language
function setLanguage(code){
backend.language = code;
}
// get the current category
function getCategory(){
return backend.category;
}
// set the current category
function setCategory(cat){
backend.category = cat;
}
// set menu from api cfg.menu object
function setMenu() {
if( typeof getConfig() !== 'undefined' && typeof getConfig().main_menu !== 'undefined' ){
var mainMenu = getConfig().main_menu;
var menu = [];
for(var i = 0; i < mainMenu.length; i++){
menu[i] = {};
// remap with fontawesome character for icon
Object.keys(mainMenu[i]).forEach(function(key, index){
if(key == 'icon' && typeof mainMenu[i][key] !== 'undefined'){
menu[i][key] = IconType[ mainMenu[i][key] ];
} else {
menu[i][key] = mainMenu[i][key];
}
}, mainMenu[i]);
}
// assign menu to listView in the menuDrawer
menuListView.model = menu;
}
}
// show custom banner
function setBanner(){
// set timeline banner from api app config
// - default values
customBar.bannerUrl = "";
customBar.bannerPartnerUrl = "";
// - overwrite values
if(typeof getConfig().timeline_banner_url !== 'undefined'){
if( getConfig().timeline_banner_url.length > 0){
// set banner image url
customBar.bannerUrl = getConfig().timeline_banner_url;
// set external url
if( typeof cfg.timeline_banner_partner_url !== 'undefined' ){
customBar.bannerPartnerUrl = getConfig().timeline_banner_partner_url;
}
} // - end if length
} // - end if typeof
}
}