ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

QML GridView 布局:网格排布与排列方向

QML GridView 布局:网格排布与排列方向

目录

    • 基础网格
      • 演示代码
    • 排列方向
      • 演示代码
    • 三个方向属性
    • 工程下载

GridView 和 ListView 的使用方式有点像,通过model提供数据、delegate定义每一项的外观。区别在于 GridView 把所有项构建成二维网格,横向、竖向两个方向都随意排列,做应用宫格、相册缩略图、图片墙都很顺手。

这篇先用最基础的写法,展示 GridView 如何构建二维网格,接着展示flow、layoutDirection、verticalLayoutDirection三个方向属性是什么效果。

基础网格

一组兴趣标签铺成网格,每项占满一个固定大小的格子,卡片之间留出间隙。

演示代码

import QtQuick import QtQuick.Controls import QtQuick.Layouts FadeInAnimation { ColumnLayout { anchors.fill: parent anchors.margins: 20 spacing: 15 // ... 省略标题组件 TitleSeparator ... // 内容卡片 Rectangle { Layout.fillWidth: true Layout.fillHeight: true color: "#fafafa" radius: 8 border.color: "#e0e0e0" border.width: 1 GridView { id: grid anchors.fill: parent anchors.margins: 10 clip: true cellWidth: 80 cellHeight: 80 model: ListModel { ListElement { name: "音乐" } ListElement { name: "电影" } ListElement { name: "读书" } ListElement { name: "旅行" } ListElement { name: "摄影" } ListElement { name: "编程" } ListElement { name: "运动" } ListElement { name: "美食" } ListElement { name: "游戏" } ListElement { name: "绘画" } ListElement { name: "烘焙" } ListElement { name: "露营" } } // delegate 占满整个单元格,内部卡片再留出间距 delegate: Item { required property int index required property string name width: grid.cellWidth height: grid.cellHeight Rectangle { anchors.fill: parent anchors.margins: 4 radius: 8 color: "#FFFFFF" border.color: "#e0e0e0" border.width: 1 Column { anchors.centerIn: parent spacing: 4 Text { anchors.horizontalCenter: parent.horizontalCenter text: name color: "#333" font.pointSize: 12 font.bold: true } Text { anchors.horizontalCenter: parent.horizontalCenter text: index + 1 color: "#999" font.pointSize: 9 } } } } } } // 状态提示 Text { Layout.fillWidth: true text: "共 " + grid.count + " 项" font.pointSize: 10 color: "#666" } } }

格子的大小由cellWidth和cellHeight决定,delegate 的根元素把宽高直接绑到这两个值上,就等于占满整个格子。

卡片本身另套一层 Rectangle,用 anchors.margins 留出 4px 间隙,相邻两项才不会挤在一起。

model 用 ListModel 描述,每个ListElement定义一个 name 字段,delegate 里用required property string name取出来。

index是网格自动给每项编的位置,从0开始,这里加1后显示在名字下面,方便对照顺序。

count是只读属性,直接读就是总项数,底部那行统计就是这么来的。

适用场景:应用宫格入口、兴趣标签墙、图片缩略图总览。


排列方向

同样的网格,用三个开关切换flow、layoutDirection、verticalLayoutDirection,能拼出好几种排布。

演示代码

import QtQuick import QtQuick.Controls import QtQuick.Layouts FadeInAnimation { ColumnLayout { anchors.fill: parent anchors.margins: 20 spacing: 15 // ... 省略标题组件 TitleSeparator ... // 控制条 RowLayout { Layout.fillWidth: true spacing: 12 // flow 可选 FlowLeftToRight / FlowTopToBottom CheckBox { id: flowCheck text: "先竖排" font.pointSize: 10 } // layoutDirection 可选 LeftToRight / RightToLeft CheckBox { id: rtlCheck text: "水平反向" font.pointSize: 10 } // verticalLayoutDirection 可选 TopToBottom / BottomToTop CheckBox { id: bottomUpCheck text: "垂直反向" font.pointSize: 10 } Item { Layout.fillWidth: true } Text { text: "共 " + grid.count + " 项" font.pointSize: 10 color: "#666" } } // 内容卡片 Rectangle { Layout.fillWidth: true Layout.fillHeight: true color: "#fafafa" radius: 8 border.color: "#e0e0e0" border.width: 1 GridView { id: grid anchors.fill: parent anchors.margins: 10 clip: true cellWidth: 70 cellHeight: 60 flow: flowCheck.checked ? GridView.FlowTopToBottom : GridView.FlowLeftToRight layoutDirection: rtlCheck.checked ? Qt.RightToLeft : Qt.LeftToRight verticalLayoutDirection: bottomUpCheck.checked ? GridView.BottomToTop : GridView.TopToBottom model: 40 delegate: Item { required property int index width: grid.cellWidth height: grid.cellHeight Rectangle { anchors.fill: parent anchors.margins: 4 radius: 8 color: "#FFFFFF" border.color: "#e0e0e0" border.width: 1 Text { anchors.centerIn: parent text: index + 1 color: "#333" font.pointSize: 12 font.bold: true } } } } } } }

flow管主方向,GridView.FlowLeftToRight 是默认值,先横着排满一行再换下一行;换成 GridView.FlowTopToBottom 后变成先竖着排满一列再排下一列,滚动方向也跟着从纵向换成横向。

layoutDirection 管水平方向,切到 Qt.RightToLeft 时格子从右边开始摆放;verticalLayoutDirection 管垂直方向,GridView.BottomToTop 让内容从底部往上填。

verticalLayoutDirection有个地方要留意:它只有在内容超过一屏时才看得出来。内容没占满视图的时候BottomToTop 和 TopToBottom 显示得一模一样,所以这个例子把项数放到了 40,专门撑出纵向滚动,勾上「垂直反向」才能看到内容从底部开始排。

另外model这里直接写了数字 40,是 GridView 的简写方式,表示有 40 项,delegate 里只能拿到index。


三个方向属性

属性控制什么取值
flow先横排还是先竖排GridView.FlowLeftToRight/GridView.FlowTopToBottom
layoutDirection水平排列方向Qt.LeftToRight/Qt.RightToLeft
verticalLayoutDirection垂直排列方向GridView.TopToBottom/GridView.BottomToTop

工程下载

  • 我的 Qt 版本:Qt 6.12
  • 操作系统:Windows 11
  • GitHub:QML 示例合集V2.0 - qml_gridview
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进