ListModel をある単位で分割したモデルを利用したい
年に一回くらいの頻度で ListView を使うけれど1画面に表示するアイテムの数は固定で SwipeView で複数ページに分けたい と思うことがあります。
ListView で縦スクロールするのではなく、SwipeView の横スクロールで表示を切り替えるってことです。
様々な理由で、おおもとのモデルは1元管理したい(もしくはしなければならない)ことが多いため、それをソースとする ProxyModel を作るのがよさそうです。
作ってみた
ソースコードは https://github.com/task-jp/paginationproxymodel を参照してください。
QML で ListModel のデータを、PagenationProxyModel というプロキシモデルでページ単位に分割しています。
import QtQuick 2.12
import QtQuick.Controls 2.5
import PaginationProxyModel 2.15
ApplicationWindow {
width: 320
height: 480
visible: true
title: 'PaginationProxyModel'
ListModel {
id: items
readonly property int countPerPage: 10
readonly property int pageCount: Math.floor((items.count + items.countPerPage - 1) / items.countPerPage)
Component.onCompleted: {
for (var i = 0; i < 21; i++)
items.append( { "text": 'Item at %1'.arg(i) })
}
}
SwipeView {
id: swipeView
anchors.fill: parent
currentIndex: tabBar.currentIndex
Repeater {
model: items.pageCount
Item {
id: delegate
property int index: model.index
ListView {
id: listView
anchors.fill: parent
interactive: false
model: PaginationProxyModel {
source: items
page: delegate.index
countPerPage: items.countPerPage
}
delegate: Text {
width: ListView.view.width
height: ListView.view.height / items.countPerPage
text: model.text
verticalAlignment: Qt.AlignVCenter
}
}
}
}
}
footer: TabBar {
id: tabBar
currentIndex: swipeView.currentIndex
Repeater {
model: items.pageCount
TabButton {
text: qsTr("Page %1").arg(model.modelData)
}
}
}
}
import QtQuick.Controls 2.5
import PaginationProxyModel 2.15
ApplicationWindow {
width: 320
height: 480
visible: true
title: 'PaginationProxyModel'
ListModel {
id: items
readonly property int countPerPage: 10
readonly property int pageCount: Math.floor((items.count + items.countPerPage - 1) / items.countPerPage)
Component.onCompleted: {
for (var i = 0; i < 21; i++)
items.append( { "text": 'Item at %1'.arg(i) })
}
}
SwipeView {
id: swipeView
anchors.fill: parent
currentIndex: tabBar.currentIndex
Repeater {
model: items.pageCount
Item {
id: delegate
property int index: model.index
ListView {
id: listView
anchors.fill: parent
interactive: false
model: PaginationProxyModel {
source: items
page: delegate.index
countPerPage: items.countPerPage
}
delegate: Text {
width: ListView.view.width
height: ListView.view.height / items.countPerPage
text: model.text
verticalAlignment: Qt.AlignVCenter
}
}
}
}
}
footer: TabBar {
id: tabBar
currentIndex: swipeView.currentIndex
Repeater {
model: items.pageCount
TabButton {
text: qsTr("Page %1").arg(model.modelData)
}
}
}
}
PagenationProxyModel の設計
おおもとのモデルに QIdentityProxyModel でページの情報を追加し、それを QSortFilterProxyModel でフィルタリングをしています。本当は両者の機能(からソートを除いた)専用のモデルを書くべきですが、それは今後の課題とします。