标签:
Qt Quick里的ListView,本身是Flickable的派生类,当你用鼠标拖曳或者手指触摸(触摸屏)时,会产生flickStarted和flickEnded两个信号,利用这两个信号,就可以实现下拉刷新数据,当然上拉刷新也是可以的。
创建一个Qt Quick App项目,添加dynamicModel.h和dynamicModel.cpp两个文件,用于实现DynamicListModel。项目创建过程参考《Qt Quick 之 Hello World 图文详解》。
我们实现的下拉刷新效果有点儿特别,每次刷新后,只保留预定义的一页数据,比如代码中默认的页大小为20。
版权所有foruok,转载请注明出处:http://blog.csdn.net/foruok。
很简单,直接上代码了。
dynamic.h:
[cpp] view plaincopy
#ifndef DYNAMICMODEL_H
#define DYNAMICMODEL_H
#include <QAbstractListModel>
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。
好啦,解说完毕。
回顾本系列文章:
标签:
原文地址:http://my.oschina.net/u/574940/blog/425520