QML Tumbler 自定义滚轮:用 PathView 实现横向选择器

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 }
    }
}

关键逻辑解析

PathViewTumbler 的最大区别在路径: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 }   // 中间:原始大小

定义之后,路径上每个位置的 itemScaleitemOpacity 都会在两端值和中间值之间平滑过渡。delegate 里直接用这两个值:

qml 复制代码
scale: PathView.itemScale
opacity: PathView.itemOpacity
font.pixelSize: 14 + PathView.itemScale * 6

于是拖动时,越靠近中间的城市越大、越清晰,越靠边越小越淡------视觉焦点自然落在中间。PathView.isCurrentItem 再给当前项加个颜色和加粗,选中状态一目了然。

preferredHighlightBegin: 0.5preferredHighlightEnd: 0.5 是让高亮位置锁定在路径的一半处(也就是正中间),配合 StrictlyEnforceRange,保证永远有一个选项停在中间,不会滚到两个选项之间卡住。dragMargin 是拖动手感:设成宽度的一半,在整条区域里拖动都灵敏。

Tumbler 对比一下:竖着滚的固定用法用 Tumbler,一行代码都不用多写;想换方向、想走曲线,就用 PathView 自己画路径,自由度完全在自己手里。

运行验证

  1. 用 Qt Creator 打开 qml_tumbler/CMakeLists.txt
  2. Ctrl+R 运行;
  3. 左侧导航切到最下面的"水平滚动",左右拖动城市列表,观察中间项放大、两边缩小的效果。

扩展复用方向

  • 把路径改成一段圆弧(用 PathQuadPathCubic),就是弧形滚轮,更像老式的滚动密码锁。
  • PathAttribute 除了缩放和透明度,还能放颜色、字号,中间高亮两边变暗的主题色滚轮就是这么做的。
  • 城市列表换成日期、数字,就是横向版本的数字选择器,适合空间紧张的工具条场景。

已验证环境

相关推荐
Quz2 小时前
QML ProgressBar 自定义样式:自绘组件、Material风格
qt
Quz2 小时前
QML 环形进度条:Canvas 绘制与多环进度
qt
熬夜苦读学习17 小时前
Qt--网络编程
开发语言·qt
上海安当技术17 小时前
C/S 桌面软件怎么接 UKey 强认证?C# SDK 与 C 动态库集成 WinForms/Qt/工控实战
c语言·qt·c#
雨田言炎19 小时前
五、Qt控件使用说明大全
开发语言·qt
熬夜苦读学习21 小时前
Qt--界面优化
开发语言·qt
Bryce学亮21 小时前
FileLine,基于 Qt 6 + QML 构建的跨平台文件传输与即时通讯工具
数据库·c++·人工智能·python·qt·github
sycmancia1 天前
Qt——复习篇painter
开发语言·qt
Quz1 天前
QML ProgressBar 基础用法:默认样式与平滑动画
qt
繁重的秋春1 天前
Qt6.0下的CMake的部署配置
qt·cmake