- SwipeView 加载大图 —
Image自适应、懒加载只建相邻页 - 自动播放与暂停 —
Timer驱动轮播,图标随状态切换 - 循环翻页 — 循环滚动图片,按钮手动翻页与定时翻页共用同一套逻辑
页面结构:SwipeView 装图片
图片浏览器的主体是占满内容区的 SwipeView,四张壁纸作为四个页面。图片资源放在工程的 wallpaper 目录并通过 res.qrc 打进 qrc:/,代码里用资源路径引用。
演示代码
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
FadeInAnimation {
id: root
function nextPhoto() {
if (swipeView.currentIndex >= swipeView.count - 1) {
swipeView.currentIndex = 0
} else {
swipeView.currentIndex++;
}
}
function prevPhoto() {
if (swipeView.currentIndex <= 0) {
swipeView.currentIndex = swipeView.count - 1
} else {
swipeView.currentIndex--;
}
}
function playAlbum() {
timer.running = !timer.running
}
Timer {
id: timer
interval: 1000
repeat: true
running: false
onTriggered: { root.nextPhoto() }
}
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 15
// ... 省略标题组件 TitleSeparator ...
SwipeView {
id: swipeView
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
Repeater {
model: [
"qrc:/wallpaper/1.png",
"qrc:/wallpaper/2.png",
"qrc:/wallpaper/3.png",
"qrc:/wallpaper/4.png"
]
Loader {
active: SwipeView.isCurrentItem || SwipeView.isNextItem || SwipeView.isPreviousItem
sourceComponent: Image {
source: modelData
anchors.fill: parent
fillMode: Image.PreserveAspectFit
}
}
}
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 60
border.width: 1
border.color: "#ccc"
radius: 6
Row {
anchors.centerIn: parent
spacing: 10
RoundButton {
width: 40
height: 40
icon.source: "qrc:/images/left.svg"
icon.width: 40
icon.height: 40
ToolTip.visible: hovered
ToolTip.text: "上一个"
onClicked: root.prevPhoto()
}
// 播放/暂停共用一个按钮,图标随自动播放状态切换
RoundButton {
width: 40
height: 40
icon.source: timer.running ? "qrc:/images/pause.svg" : "qrc:/images/play.svg"
icon.width: 40
icon.height: 40
ToolTip.visible: hovered
ToolTip.text: timer.running ? "暂停播放" : "自动播放"
onClicked: root.playAlbum()
}
RoundButton {
width: 40
height: 40
icon.source: "qrc:/images/right.svg"
icon.width: 40
icon.height: 40
ToolTip.visible: hovered
ToolTip.text: "下一个"
onClicked: root.nextPhoto()
}
}
}
}
}
关键逻辑解析
页面模型直接放图片路径数组。Repeater 的 model 是四个 qrc:/wallpaper/*.png 字符串,delegate 里用 modelData 取出当前项当图片地址,一个 Image 就渲染出了四页。比逐个手写 Image 干净,加第五张图只需往数组里加一行。
图片要用 anchors.fill + PreserveAspectFit 适配。壁纸是 1060×596 的横屏大图,而页面区域小得多。不给 Image 设置布局它会按隐式尺寸显示左上角一块;anchors.fill: parent 让图片占满整页,fillMode: Image.PreserveAspectFit 则等比缩放、完整显示、四周留白,既不裁图也不变形。
Loader 三条件懒加载在这里同样适用。大图解码费内存,四张一起建不如只建当前页和左右相邻页。SwipeView.isCurrentItem / isNextItem / isPreviousItem 保证滑动动画始终有图可画,滑远的页面自动销毁释放内存。
控制逻辑:翻页、轮播与暂停
页面本身只有滑动能力,上一张/下一张/自动播放全靠底下三个按钮 + 一个 Timer 驱动 currentIndex 实现。
关键逻辑解析
手动翻页是"边界回绕"的算术。nextPhoto:已在最后一页就跳回 0,否则 currentIndex++;prevPhoto 对称:已在第一页就跳到最后一张。四张图循环浏览,怎么滑都不会越界。按钮的 onClicked 直接调用这两个函数即可。
自动播放是 Timer 周期调用 nextPhoto。Timer 每 1000ms 触发一次 onTriggered,内部调用 root.nextPhoto()——轮播本质就是"定时翻下一页"。repeat: true 让它一直跑,running 控制启停。
播放/暂停共用一个按钮,靠 timer.running 切图标和提示。中间按钮的 icon.source 写成 timer.running ? "pause.svg" : "play.svg",跑着显示暂停图标、停着显示播放图标;ToolTip.text 同理在「暂停播放 / 自动播放」间切换。用户悬停能看到下一步动作,点按结果和图标一致,不需要第二个"状态灯"。
playAlbum 只做一件事:翻转 running。timer.running = !timer.running,播放中点了变暂停,暂停中点了继续。没有多余状态变量,running 本身就是唯一状态源,所有 UI 都从它派生。
整体布局:图片区与底部控制条
去掉指示器后,界面只剩两个区域,都由 ColumnLayout 从上往下排:SwipeView 图片区占满剩余空间(Layout.fillHeight: true),底部的控制条是一个带圆角边框的 Rectangle,固定 preferredHeight: 60,三个 RoundButton 用 Row 居中排布。要不要"当前第几张"的提示?这个 demo 选择了不加——四张图循环浏览,回绕行为让"在哪一张"变得不那么关键,把指示器留给需要精确定位的场景(如第一篇的自定义指示器 demo),图片浏览器保持纯粹的两段式结构。
运行验证
- Qt Creator 打开
qml_swipeview/CMakeLists.txt,按Ctrl+R运行; - 左侧点「图片浏览器(简易版)」,拖拽图片左右滑动,观察图片自适应缩放、四周留白;
- 点右侧「下一个」到底后继续点,看是否回绕到第一张;点左侧「上一个」同理;
- 点中间播放按钮,图片每 1 秒自动切换,图标变暂停;再点一下停止轮播,图标恢复播放,悬停查看 ToolTip 文案变化。
扩展复用方向
- 图片路径数组换成
ListModel,就能支持运行时增删照片、显示文件名等信息; - 把
Timer.interval做成滑块可调,就是"播放速度"设置项; - 想加"点击图片看大图"或双击放大,在
Image外包一层MouseArea即可,轮播逻辑不受影响。
已验证环境:
- Qt 版本:Qt 6.8.2 / Qt 6.11.1
- 操作系统:Windows 11
- GitHub:QML-Minimal-Demos/qml_swipeview
示例代码短小完整,懒加载与单一状态源思路值得借鉴,适合需要图片轮播或相册翻页的 QML 初学者直接套用。