Tumbler 的滚轮是竖着滚的,想横着滚怎么办?Tumbler 本身不支持换方向,但 QML 里有个更灵活的组件叫 PathView------它可以让选项沿着任意路径排列。这篇把路径设成一条水平线,做一个横向的城市选择器,效果和 iOS 上横向滑动的选择器一个路子。
Demo 1:水平滚动
一排城市名横向排列,拖动时中间的城市放大变清晰,两边的缩小变淡,停在中间的就是选中项。

演示代码
qml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
FadeInAnimation {
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 15
// ... 省略标题组件 TitleSeparator ...
PathView {
id: pathView
Layout.fillWidth: true
Layout.preferredHeight: 200
Layout.alignment: Qt.AlignHCenter
model: ["北京", "上海", "广州", "深圳", "杭州", "成都", "武汉", "南京", "西安", "重庆"]
currentIndex: 2
pathItemCount: 7
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
highlightRangeMode: PathView.StrictlyEnforceRange
dragMargin: pathView.width / 2
path: Path {
startX: 0
startY: pathView.height / 2
PathAttribute { name: "itemScale"; value: 0.6 }
PathAttribute { name: "itemOpacity"; value: 0.3 }
PathLine { x: pathView.width / 2; y: pathView.height / 2 }
PathAttribute { name: "itemScale"; value: 1.0 }
PathAttribute { name: "itemOpacity"; value: 1.0 }
PathLine { x: pathView.width; y: pathView.height / 2 }
PathAttribute { name: "itemScale"; value: 0.6 }
PathAttribute { name: "itemOpacity"; value: 0.3 }
}
delegate: Text {
width: 80
height: pathView.height
text: modelData
font.pixelSize: 14 + PathView.itemScale * 6
color: PathView.isCurrentItem ? "#e91e63" : "#333"
font.bold: PathView.isCurrentItem
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
opacity: PathView.itemOpacity
scale: PathView.itemScale
}
// 中间高亮背景
Rectangle {
width: 80
height: parent.height * 0.55
radius: 8
color: "#e91e63"
opacity: 0.12
x: parent.width / 2 - width / 2
y: parent.height / 2 - height / 2
}
}
Text {
Layout.alignment: Qt.AlignHCenter
text: "当前选择: " + pathView.model[pathView.currentIndex]
font.pointSize: 13
color: "#e91e63"
font.bold: true
}
Item { Layout.fillHeight: true }
}
}
关键逻辑解析
PathView 和 Tumbler 的最大区别在路径:Tumbler 的滚动路线写死了是竖线,PathView 可以自由定义。这里把路径画成一条从左到右的水平线:
qml
path: Path {
startX: 0
startY: pathView.height / 2
PathLine { x: pathView.width / 2; y: pathView.height / 2 }
PathLine { x: pathView.width; y: pathView.height / 2 }
}
startX/startY 是起点,PathLine 一段段连过去------起点、中间、终点都在垂直居中位置,选项就沿着这条线横向排列。
但光有路径,所有城市长得一模一样,看不出哪个是当前的。PathAttribute 就是干这个的:它可以给路径上的不同位置"贴标签"。
qml
PathAttribute { name: "itemScale"; value: 0.6 } // 两端:缩小到 0.6
PathAttribute { name: "itemScale"; value: 1.0 } // 中间:原始大小
定义之后,路径上每个位置的 itemScale、itemOpacity 都会在两端值和中间值之间平滑过渡。delegate 里直接用这两个值:
qml
scale: PathView.itemScale
opacity: PathView.itemOpacity
font.pixelSize: 14 + PathView.itemScale * 6
于是拖动时,越靠近中间的城市越大、越清晰,越靠边越小越淡------视觉焦点自然落在中间。PathView.isCurrentItem 再给当前项加个颜色和加粗,选中状态一目了然。
preferredHighlightBegin: 0.5 配 preferredHighlightEnd: 0.5 是让高亮位置锁定在路径的一半处(也就是正中间),配合 StrictlyEnforceRange,保证永远有一个选项停在中间,不会滚到两个选项之间卡住。dragMargin 是拖动手感:设成宽度的一半,在整条区域里拖动都灵敏。
和 Tumbler 对比一下:竖着滚的固定用法用 Tumbler,一行代码都不用多写;想换方向、想走曲线,就用 PathView 自己画路径,自由度完全在自己手里。
运行验证
- 用 Qt Creator 打开
qml_tumbler/CMakeLists.txt; - 按
Ctrl+R运行; - 左侧导航切到最下面的"水平滚动",左右拖动城市列表,观察中间项放大、两边缩小的效果。
扩展复用方向
- 把路径改成一段圆弧(用
PathQuad或PathCubic),就是弧形滚轮,更像老式的滚动密码锁。 PathAttribute除了缩放和透明度,还能放颜色、字号,中间高亮两边变暗的主题色滚轮就是这么做的。- 城市列表换成日期、数字,就是横向版本的数字选择器,适合空间紧张的工具条场景。
已验证环境:
- Qt 版本:Qt 6.8.2 / Qt 6.11.1
- 操作系统:Windows 11
- GitHub:QML-Minimal-Demos/qml_tumbler