You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 10:34:56