如何在QML的GridView中实现滑动分页展示条目?
实现GridView分页滚动(整页切换)
需求说明
我需要实现这样的效果:滑动GridView时,一组条目作为一页滚动,下一组条目展示在下一页。比如总共有20个条目时,第一页显示10个,第二页显示10个;如果条目超过20个,剩余的条目自动生成第三页。以下是我尝试的代码:
原尝试代码
GridExample.qml
import QtQml 2.12 import QtQuick 2.12 import QtQml.Models 2.12 GridView { id: root width: 320; height: 200 cellWidth: 80; cellHeight: 80 displaced: Transition { NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad } } flow: Grid.TopToBottom model: DelegateModel { id: visualModel model: ListModel { id: colorModel ListElement { color: "blue" } ListElement { color: "green" } ListElement { color: "red" } ListElement { color: "yellow" } ListElement { color: "orange" } ListElement { color: "purple" } ListElement { color: "cyan" } ListElement { color: "magenta" } ListElement { color: "chartreuse" } ListElement { color: "aquamarine" } ListElement { color: "indigo" } ListElement { color: "black" } ListElement { color: "lightsteelblue" } ListElement { color: "violet" } ListElement { color: "grey" } ListElement { color: "springgreen" } ListElement { color: "salmon" } ListElement { color: "blanchedalmond" } ListElement { color: "forestgreen" } ListElement { color: "pink" } ListElement { color: "navy" } ListElement { color: "goldenrod" } ListElement { color: "crimson" } ListElement { color: "teal" } ListElement { color: "springgreen" } ListElement { color: "salmon" } ListElement { color: "blanchedalmond" } ListElement { color: "forestgreen" } ListElement { color: "pink" } ListElement { color: "navy" } ListElement { color: "goldenrod" } ListElement { color: "crimson" } ListElement { color: "teal" } } delegate: DropArea { id: delegateRoot required property color color width: 80; height: 80 onEntered: function(drag) { visualModel.items.move((drag.source as Icon).visualIndex, icon.visualIndex) } property int visualIndex: DelegateModel.itemsIndex Icon { id: icon dragParent: root visualIndex: delegateRoot.visualIndex color: delegateRoot.color } } } }
Icon.qml
import QtQuick 2.15 Rectangle { id: icon required property Item dragParent property int visualIndex: 0 width: 72 height: 72 anchors { horizontalCenter: parent.horizontalCenter verticalCenter: parent.verticalCenter } radius: 3 Text { anchors.centerIn: parent color: "white" text: parent.visualIndex } DragHandler { id: dragHandler } Drag.active: dragHandler.active Drag.source: icon Drag.hotSpot.x: 36 Drag.hotSpot.y: 36 states: [ State { when: dragHandler.active ParentChange { target: icon parent: icon.dragParent } AnchorChanges { target: icon anchors.horizontalCenter: undefined anchors.verticalCenter: undefined } } ] }
解决方案
要实现整页滚动效果,需要用Flickable包裹GridView,并配置滚动吸附逻辑,同时动态计算分页参数。修改后的GridExample.qml如下:
import QtQml 2.12 import QtQuick 2.12 import QtQml.Models 2.12 Flickable { id: flickableRoot width: 320 height: 200 // 滚动到整页位置时自动吸附 snapMode: Flickable.SnapToItem snapAlignment: Qt.AlignTop // 每页显示的条目数量 property int itemsPerPage: 10 // 计算GridView的列数 property int columns: Math.floor(width / gridView.cellWidth) // 计算每页需要的行数 property int rowsPerPage: Math.ceil(itemsPerPage / columns) // 计算每页的高度 property real pageHeight: rowsPerPage * gridView.cellHeight GridView { id: gridView width: flickableRoot.width // GridView总高度 = 总页数 × 每页高度 height: Math.ceil(visualModel.model.count / itemsPerPage) * pageHeight cellWidth: 80 cellHeight: 80 displaced: Transition { NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad } } flow: Grid.TopToBottom model: DelegateModel { id: visualModel model: ListModel { id: colorModel ListElement { color: "blue" } ListElement { color: "green" } ListElement { color: "red" } ListElement { color: "yellow" } ListElement { color: "orange" } ListElement { color: "purple" } ListElement { color: "cyan" } ListElement { color: "magenta" } ListElement { color: "chartreuse" } ListElement { color: "aquamarine" } ListElement { color: "indigo" } ListElement { color: "black" } ListElement { color: "lightsteelblue" } ListElement { color: "violet" } ListElement { color: "grey" } ListElement { color: "springgreen" } ListElement { color: "salmon" } ListElement { color: "blanchedalmond" } ListElement { color: "forestgreen" } ListElement { color: "pink" } ListElement { color: "navy" } ListElement { color: "goldenrod" } ListElement { color: "crimson" } ListElement { color: "teal" } ListElement { color: "springgreen" } ListElement { color: "salmon" } ListElement { color: "blanchedalmond" } ListElement { color: "forestgreen" } ListElement { color: "pink" } ListElement { color: "navy" } ListElement { color: "goldenrod" } ListElement { color: "crimson" } ListElement { color: "teal" } } delegate: DropArea { id: delegateRoot required property color color width: 80; height: 80 onEntered: function(drag) { visualModel.items.move((drag.source as Icon).visualIndex, icon.visualIndex) } property int visualIndex: DelegateModel.itemsIndex Icon { id: icon dragParent: flickableRoot visualIndex: delegateRoot.visualIndex color: delegateRoot.color } } } } // 可选:添加页码指示器,显示当前页和总页数 PageIndicator { id: pageIndicator anchors.bottom: flickableRoot.bottom anchors.horizontalCenter: flickableRoot.horizontalCenter count: Math.ceil(visualModel.model.count / itemsPerPage) currentIndex: Math.floor(flickableRoot.contentY / pageHeight) } }
关键实现要点
- Flickable包裹:利用
Flickable的滚动吸附能力,设置snapMode: SnapToItem和snapAlignment: Qt.AlignTop,确保滚动停止时自动对齐到整页顶部。 - 动态分页计算:通过
itemsPerPage定义每页条目数,结合列数计算每页所需行数和高度,再根据总条目数动态计算GridView的总高度。 - 页码指示器:可选添加
PageIndicator,让用户直观看到当前页码和总页数,提升交互体验。 - 拖拽兼容:保持原有的拖拽排序逻辑,仅修改滚动相关部分,不影响原有功能。
内容的提问来源于stack exchange,提问作者Pranav N Rao
相关产品推荐
相关产品推荐

