Qt qml listview下拉刷新和上拉分頁主要根據contentY來判斷。但要加上頂部下拉指示器、滾動條,並封裝成可簡單調用的組件,着實花了我很多精力:)app
【先看效果】工具
【功能】spa
1 下拉刷新和上拉分頁邏輯 2 /下拉刷新 3 /上拉更多 4 /滾動欄 5 /工具欄半拉顯隱 6 Author: surfsky.cnblogs.com 7 Lisence: MIT 請保留此文檔聲明 8 History: 9 init. surfsky.cnblogs.com, 2015-01 10 add initPosition property. 2015-01
【下載】.net
http://download.csdn.net/detail/surfsky/8516981代理
【調用】code
控件使用很是簡單,只要實現 onLoad 和 onLoadMore 事件便可,其餘的和標準的ListView差很少。blog
1 /** 2 新聞示例 3 下拉刷新 4 上拉分頁 5 滾動軸 6 頂部工具欄 7 頂部工具欄自動吸附 8 當前行高亮 9 Author: surfsky.cnblogs.com 2015-01 10 */ 11 ListViewEx{ 12 id: view 13 width: 500 14 height: 800 15 pageSize: 50 16 snapHeader: true 17 initPosition: 'header' 18 19 // 頂部新聞圖片欄 20 headerComponent: Component{ 21 PageView{ 22 id: pv 23 width: view.width 24 height: 100 25 clip: true 26 Rectangle{width:pv.width; height:pv.height; color: 'green'} 27 Rectangle{width:pv.width; height:pv.height; color: 'yellow'} 28 Rectangle{width:pv.width; height:pv.height; color: 'blue'} 29 } 30 } 31 32 // 行UI代理 33 delegate: Text { 34 id: wrapper; 35 width: parent.width; 36 height: 32; 37 font.pointSize: 15; 38 verticalAlignment: Text.AlignVCenter; 39 horizontalAlignment: Text.AlignHCenter; 40 text: content; 41 //color: ListView.view.currentIndex == index ? "white" : "#505050"; 42 MouseArea { 43 anchors.fill: parent; 44 onClicked: wrapper.ListView.view.currentIndex = index; 45 } 46 } 47 48 49 //----------------------------------------- 50 // 數據加載事件 51 //----------------------------------------- 52 onLoad:{ 53 for (var i = 0 ; i < pageSize ; ++i) 54 model.append({"index": i, "content": "Item " + i}) 55 } 56 onLoadMore:{ 57 for (var i = pageSize*page ; i < pageSize*(page+1); ++i) 58 model.append({"index": i, "content": "Item " + i}) 59 } 60 }
【核心代碼】事件
實在太長了,截取ContentY處理部分,其餘的下載了看吧圖片
1 //------------------------------------- 2 // 下拉刷新和上拉分頁邏輯 3 //------------------------------------- 4 onMovementEnded: { 5 //console.log("movementEnded: originY:" + originY + ", contentY:" + contentY + ", reflesh:" + needReflesh + ", more:" + needLoadMore); 6 // 刷新數據 7 if (needReflesh){ 8 lv.headerItem.goState('load'); 9 model.reflesh(); 10 needReflesh = false; 11 } 12 // 加載新數據 13 else if (needLoadMore){ 14 model.loadMore(); 15 needLoadMore = false; 16 } 17 else { 18 var h1 = lv.headerItem.loader.height; 19 var h2 = lv.headerItem.indicator.height; 20 21 // 頭部區自動顯隱(拖動太小隱藏頭部,反之顯示) 22 if (snapHeader){ 23 if (contentY >= -h1/3 && contentY < 0) 24 moveToFirst(); 25 if (contentY >= -h1 && contentY < -h1/3) 26 moveToHeader(); 27 } 28 // 刷新區自動顯隱 29 if (contentY >=-(h1+h2) && contentY < -h1) 30 moveToHeader(); 31 } 32 } 33 onContentYChanged: { 34 // 下拉刷新判斷邏輯:已經到頭了,還下拉必定距離 35 if (contentY < originY){ 36 var dy = contentY - originY; 37 if (dy < -10){ 38 lv.headerItem.goState('ready'); 39 needReflesh = true; 40 } 41 else { 42 if (pressed){ 43 //console.log(pressed); 44 //needReflesh = false; // 如何判斷當前鼠標是否按下?若是是按下狀態才能取消刷新 45 lv.headerItem.goState(''); 46 } 47 } 48 } 49 // 上拉加載判斷邏輯:已經到底了,還上拉必定距離 50 if (contentHeight>height && contentY-originY > contentHeight-height){ 51 var dy = (contentY-originY) - (contentHeight-height); 52 //console.log("y: " + contentY + ", dy: " + dy); 53 if (dy > 40){ 54 needLoadMore = true; 55 //console.log("originY:" + originY + ", contentY:" + contentY + ", height:" + height + ", contentheight:" + contentHeight); 56 } 57 } 58 }