Qt Quick裏的ListView,自己是Flickable的派生類,當你用鼠標拖曳或者手指觸摸(觸摸屏)時,會產生flickStarted和flickEnded兩個信號,利用這兩個信號,就能夠實現下拉刷新數據,固然上拉刷新也是能夠的。javascript
建立一個Qt Quick App項目,添加dynamicModel.h和dynamicModel.cpp兩個文件,用於實現DynamicListModel。項目建立過程參考《Qt Quick 之 Hello World 圖文詳解》。java
咱們實現的下拉刷新效果有點兒特別,每次刷新後,只保留預約義的一頁數據,好比代碼中默認的頁大小爲20。編程
版權全部foruok,轉載請註明出處:http://blog.csdn.net/foruok。app
很簡單,直接上代碼了。函數
dynamic.h:佈局
[cpp] view plaincopyui
#ifndef DYNAMICMODEL_H this
#define DYNAMICMODEL_H spa
#include <QAbstractListModel> .net
class DynamicListModelPrivate;
class DynamicListModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int pageSize READ pageSize WRITE setPageSize NOTIFY pageSizeChanged)
Q_PROPERTY(int total READ total WRITE setTotal NOTIFY totalChanged)
public:
DynamicListModel(QObject *parent = 0);
~DynamicListModel();
int rowCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
QHash<int, QByteArray> roleNames() const;
Q_INVOKABLE void loadMore(bool forward);
int pageSize();
void setPageSize(int size);
int total();
void setTotal(int total);
signals:
void pageSizeChanged(int size);
void totalChanged(int total);
private:
DynamicListModelPrivate *m_dptr;
};
#endif // DYNAMICMODEL_H
dynamicModel.cpp:
[cpp] view plaincopy
#include "dynamicModel.h"
#include <QDebug>
class DynamicListModelPrivate
{
public:
DynamicListModelPrivate(DynamicListModel *model)
: m_model(model), m_start(0), m_end(20)
, m_total(100), m_pageSize(20)
{
m_roleNames.insert(Qt::UserRole, "content");
}
void pageDown()
{
if(m_end < m_total)
{
m_start += m_pageSize;
m_end += m_pageSize;
if(m_end > m_total)
{
m_end = m_total;
m_start = m_end - m_pageSize;
}
}
}
void pageUp()
{
if(m_start > 0)
{
m_start -= m_pageSize;
if(m_start < 0) m_start = 0;
m_end = m_start + m_pageSize;
}
}
void adjustPageRange()
{
if(m_end - m_start < m_pageSize)
{
m_end = m_start + m_pageSize;
if(m_end > m_total)
{
m_end = m_total;
m_start = m_end - m_pageSize;
}
}
}
DynamicListModel *m_model;
int m_start;
int m_end;
int m_total;
int m_pageSize;
QHash<int, QByteArray> m_roleNames;
};
DynamicListModel::DynamicListModel(QObject *parent)
: QAbstractListModel(parent),
m_dptr(new DynamicListModelPrivate(this))
{
}
DynamicListModel::~DynamicListModel()
{
delete m_dptr;
}
int DynamicListModel::rowCount(const QModelIndex &parent) const
{
return m_dptr->m_end - m_dptr->m_start;
}
QVariant DynamicListModel::data(const QModelIndex &index, int role) const
{
int row = index.row();
//qDebug() << "index.row - " << row << " start - " << m_dptr->m_start;
return QString::number(row + m_dptr->m_start);
}
QHash<int, QByteArray> DynamicListModel::roleNames() const
{
return m_dptr->m_roleNames;
}
void DynamicListModel::loadMore(bool forward)
{
beginResetModel();
if(forward)m_dptr->pageDown();
else m_dptr->pageUp();
endResetModel();
}
int DynamicListModel::pageSize()
{
return m_dptr->m_pageSize;
}
void DynamicListModel::setPageSize(int size)
{
m_dptr->m_pageSize = size;
m_dptr->adjustPageRange();
emit pageSizeChanged(size);
}
int DynamicListModel::total()
{
return m_dptr->m_total;
}
void DynamicListModel::setTotal(int total)
{
m_dptr->m_total = total;
m_dptr->adjustPageRange();
emit totalChanged(total);
}
DynamicListModel僅僅是演示用法,使用m_start、m_end、m_total、m_pageSize四個整型變量來模擬實際的數 據。而data()方法,將ListView內的行序號加上m_start轉換爲字符串返回,就是咱們在ListView界面上看到了文字了。
loadMore()函數,區分向前仍是向後加載數據,它調用DynamicListModel的pageDown()、pageUp()來更新內部的數 據狀態。在loadMore()一開始,調用beginResetModel(),通知關聯到DynamicListModel上的view們刷新本身, 當內部數據狀態更新結束後,調用endResetModel()來通知view們,這樣view們就會刷新,最終在實例化item delegate時調用data()方法來準備數據,此時m_start已變化,因此界面上看到的數字也跟着變了。
這個簡單,咱們在《Qt Quick 之 QML 與 C++ 混合編程詳解》一文中已經講過。直接看main.cpp:
[cpp] view plaincopy
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "dynamicModel.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
QQmlContext *ctx = engine.rootContext();
ctx->setContextProperty("dynamicModel", new DynamicListModel());
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
return app.exec();
}
是時候看看main.qml了:
[javascript] view plaincopy
import QtQuick 2.2
import QtQuick.Window 2.1
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.2
Window {
width: 320;
height: 480;
minimumWidth: 300;
minimumHeight: 480;
visible: true;
id: root;
Component {
id: listDelegate;
Text {
id: wrapper;
width: parent.width;
height: 32;
font.pointSize: 15;
verticalAlignment: Text.AlignVCenter;
horizontalAlignment: Text.AlignHCenter;
text: content;
color: ListView.view.currentIndex == index ? "red" : "blue";
MouseArea {
anchors.fill: parent;
onClicked: {
if(wrapper.ListView.view.currentIndex != index){
wrapper.ListView.view.currentIndex = index;
}
}
}
}
}
ListView {
id: dynamicList;
z: 1;
anchors.fill: parent;
anchors.margins: 10;
delegate: listDelegate;
model: dynamicModel;
focus: true;
activeFocusOnTab: true;
highlight: Rectangle {
color: "steelblue";
}
property real contentYOnFlickStarted: 0;
onFlickStarted: {
//console.log("start,origY - ", originY, " contentY - ", contentY);
contentYOnFlickStarted = contentY;
}
onFlickEnded: {
//console.log("end,origY - ", originY, " contentY - ", contentY);
dynamicModel.loadMore(contentY < contentYOnFlickStarted);
}
}
}
定義ListView對象時,指定其model爲main()函數中導出的dynamicModel,其它的代碼沒必要細說了,我們單看實現下拉(上拉)刷新的關鍵代碼。
onFlickStarted信號處理器,在這裏咱們僅僅是將flick開始時的contentY記錄到contentYOnFlickStarted屬性中。
onFlickEnded信號處理器,這裏比較flick結束時的contentY和開始時的contentY(即contentYOnFlickStarted),結束時小,說明是下拉,結束時大,說明是上拉。根據比較結果調用loadMore()。
好啦,就這麼簡單了。看看效果。
圖1是初始效果:
圖1動態刷新列表初始效果
圖2是下拉了兩次後的效果:
圖2 下拉刷新後的效果
圖3是從圖2所示狀態上拉後的效果:
圖3 上拉後的效果
版權全部foruok,轉載請註明出處:http://blog.csdn.net/foruok。
好啦,解說完畢。
回顧本系列文章: