QML 里最常用的滚动方式有:用ScrollView组件直接包起来、在Flickable组件中加上ScrollBar。如果只想显示提示不让人拖动就用ScrollIndicator。
这篇文章用三个 demo 把基础用法过一遍,看完就知道该选哪个。
ScrollView 滚动
一个简单的滚动示例:
演示代码
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
FadeInAnimation {
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 15
// ... 省略标题组件 TitleSeparator ...
ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ScrollBar.vertical.interactive: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 10
Repeater {
model: 20
delegate: ItemDelegate {
background: Rectangle {
implicitWidth: 150
implicitHeight: 25
color: "#3498db"
radius: 4
}
contentItem: Text {
text: "This is Scroll Item " + index
color: "#fff"
}
}
}
}
}
}
}
直接使用 ScrollView 比较省事,用户只需要把内容丢进去,滚动条自动就有了。policy: AsNeeded 表示内容装不下时才显示滚动条,放得下就自动藏起来;interactive: true 表示滑块能用鼠标直接拖动。
这个演示demo里使用 Repeater 一次性生成了 20 条条目,把内容撑出可视高度,自然就能上下滚动。适用场景:设置页、长表单、条目数不定的纵向列表。
Flickable 双向滚动
当内容横竖都超出视图时,垂直、水平两条滚动条同时出现。
演示代码
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
FadeInAnimation {
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 15
// ... 省略标题组件 TitleSeparator ...
Flickable {
id: flickable
Layout.fillWidth: true
Layout.fillHeight: true
clip: true // 防止内容超出边界
contentWidth: contentRect.width
contentHeight: contentRect.height
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AlwaysOn }
ScrollBar.horizontal: ScrollBar { policy: ScrollBar.AlwaysOn }
Rectangle {
id: contentRect
width: 500
height: 500
color: "#3498db"
Text {
text: "Scrollable Content"
anchors.centerIn: parent
font.pointSize: 20
color: "#fff"
}
}
}
}
}
Flickable 本身只负责让内容能动起来,滚动条需要自己加上,默认不显示。ScrollBar.vertical 和 ScrollBar.horizontal 这两个附加属性,就是分别对应垂直、水平方向的滚动条。
想让内容滚得动,contentWidth 和 contentHeight 必须设成内容的真实宽高——视口比内容小,才有东西可以滚;clip: true 再把超出框的内容裁掉,不然会露到外面。这里 policy 用了 AlwaysOn,两条滚动条一直显示,方便看效果。
和 ScrollView 比:ScrollView 开箱即用,但能调的东西不多;Flickable 什么都能自己定,代价是滚动条、裁剪这些都得自己动手。
适用场景:画布、大图预览、需要横向纵向都平移的区域。
ScrollIndicator 指示器
只用于进度指示:
演示代码
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
FadeInAnimation {
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 15
// ... 省略标题组件 TitleSeparator ...
Flickable {
id: flickable
Layout.fillWidth: true
Layout.fillHeight: true
clip: true // 防止内容超出边界
contentWidth: contentRect.width
contentHeight: contentRect.height
// 与ScrollBar的区别是不可交互,仅提供视觉指示,
// ScrollIndicator不能用在ScrollView中,
// 否则报错:ScrollIndicator must be attached to a Flickable.
ScrollIndicator.vertical: ScrollIndicator {
contentItem: Rectangle {
implicitWidth: 6
color: "#ccc"
radius: 3
}
}
Rectangle {
id: contentRect
width: 500
height: 500
color: "#3498db"
Text {
text: "Scrollable Content"
anchors.centerIn: parent
font.pointSize: 20
color: "#fff"
}
}
}
}
}
ScrollIndicator 和 ScrollBar 长得很像,但它只能看不能拖,是纯视觉提示用的。它还有个硬性限制:只能附加在 Flickable 上,不能写进 ScrollView 里,硬写会直接报错。
新手最容易把 ScrollBar 和 ScrollIndicator 搞混,记一个判断标准就够了:能拖的叫 ScrollBar,只能看的叫 ScrollIndicator。
适用场景:只读浏览、不想让用户拖进度的翻页式内容。
什么场景用哪个
| 场景 | 用哪个 |
|---|---|
| 纵向列表,内容包起来就能滚 | ScrollView |
| 横竖都要滚,或要自己控制滚动行为 | Flickable + ScrollBar |
| 只提示位置,不允许拖动 | ScrollIndicator |
已验证环境:
- Qt 版本:Qt 6.8.2、Qt 6.11.1
- 操作系统:Windows 11
- GitHub:QML-Minimal-Demos/qml_scrollbar