Flickable 是 QML 中用于创建可滚动区域的基础组件,它比 ScrollView 提供更底层的控制,适合需要自定义滚动行为的场景。
基本用法
qml
import QtQuick 2.15Flickable {width: 200height: 200contentWidth: 400  // 内容总宽度contentHeight: 800 // 内容总高度// 内容项Rectangle {width: 400height: 800gradient: Gradient {GradientStop { position: 0.0; color: "red" }GradientStop { position: 1.0; color: "blue" }}}
} 
Flickable 属性表
1. 核心属性
| 属性 | 类型 | 默认值 | 说明 | 
|---|---|---|---|
contentWidth | real | 0 | 必须设置 - 内容区域的总宽度 | 
contentHeight | real | 0 | 必须设置 - 内容区域的总高度 | 
contentX | real | 0 | 当前水平滚动位置(可读写) | 
contentY | real | 0 | 当前垂直滚动位置(可读写) | 
clip | bool | false | 是否裁剪超出部分(建议设为 true) | 
interactive | bool | true | 是否允许用户交互滚动 | 
2. 滚动行为控制
| 属性 | 类型 | 默认值 | 说明 | 
|---|---|---|---|
boundsBehavior | enum | Flickable.StopAtBounds | 边界行为:StopAtBounds - 不能拖出边界DragOverBounds - 可拖出边界(有回弹)OvershootBounds - 允许短暂超出 | 
flickableDirection | enum | AutoFlickDirection | 滚动方向:HorizontalFlick - 仅水平VerticalFlick - 仅垂直HorizontalAndVerticalFlick - 双向AutoFlickDirection - 自动判断 | 
maximumFlickVelocity | real | 2500 | 最大滚动速度(像素/秒) | 
flickDeceleration | real | 1500 | 滚动减速系数(值越大停止越快) | 
pressDelay | int | 0 | 触摸按下延迟(毫秒) | 
3. 只读属性
| 属性 | 类型 | 说明 | 
|---|---|---|
dragging | bool | 是否正在拖动 | 
flicking | bool | 是否正在惯性滚动 | 
moving | bool | 是否正在移动(拖动或惯性滚动) | 
visibleArea | object | 包含:widthRatio - 可见宽度比例heightRatio - 可见高度比例xPosition - 水平位置(0.0-1.0)yPosition - 垂直位置(0.0-1.0) | 
4. 信号
| 信号 | 参数 | 说明 | 
|---|---|---|
movementStarted() | - | 开始滚动时触发 | 
movementEnded() | - | 滚动停止时触发 | 
flickStarted() | - | 惯性滚动开始时触发 | 
flickEnded() | - | 惯性滚动结束时触发 | 
contentXChanged() | real | 水平位置变化时触发 | 
contentYChanged() | real | 垂直位置变化时触发 | 
5. 常用方法
| 方法 | 参数 | 说明 | 
|---|---|---|
flick(vx, vy) | vx: 水平速度vy: 垂直速度 | 以指定速度触发惯性滚动 | 
cancelFlick() | - | 立即停止惯性滚动 | 
returnToBounds() | - | 强制回到边界内 | 
完整示例代码
import QtQuick 2.15Flickable {id: flickwidth: 300height: 400contentWidth: contentItem.widthcontentHeight: contentItem.heightclip: trueboundsBehavior: Flickable.DragOverBounds// 内容项Grid {id: contentItemwidth: 600height: 800columns: 3spacing: 10Repeater {model: 50Rectangle {width: 180; height: 180color: Qt.hsla(index/50, 0.8, 0.6, 1)Text { text: index; anchors.centerIn: parent }}}}// 监听滚动onContentYChanged: console.log("Y位置:", contentY)onMovementEnded: console.log("滚动停止")// 滚动到指定位置function scrollToBottom() {contentY = contentHeight - height}
} 
滚动行为控制
qml
Flickable {// 启用水平和垂直滚动flickableDirection: Flickable.HorizontalAndVerticalFlick// 允许拖动超出边界(会有回弹效果)boundsBehavior: Flickable.DragOverBounds// 滚动速度系数flickDeceleration: 1500// 最大速度限制maximumFlickVelocity: 2500
} 
与 ScrollBar 配合使用
qml
import QtQuick 2.15
import QtQuick.Controls 2.15Flickable {id: flickwidth: 200height: 200contentWidth: 400contentHeight: 800// 内容项...// 垂直滚动条ScrollBar.vertical: ScrollBar {policy: ScrollBar.AsNeededsize: flick.height / flick.contentHeightposition: flick.visibleArea.yPosition}// 水平滚动条ScrollBar.horizontal: ScrollBar {policy: ScrollBar.AsNeededsize: flick.width / flick.contentWidthposition: flick.visibleArea.xPosition}
} 
可见区域计算
qml
Flickable {// 获取可见区域比例和位置property real visibleWidthRatio: visibleArea.widthRatioproperty real visibleHeightRatio: visibleArea.heightRatioproperty real visibleXPosition: visibleArea.xPositionproperty real visibleYPosition: visibleArea.yPosition
} 
高级用法
1. 滚动到指定位置
qml
// 滚动到水平中心
flick.contentX = (flick.contentWidth - flick.width) / 2// 带动画效果
NumberAnimation {target: flickproperty: "contentX"to: targetValueduration: 500easing.type: Easing.InOutQuad
}.start() 
2. 嵌套 Flickable
qml
Flickable {// 外部FlickableFlickable {// 内部Flickable// 需要处理事件传递onMovementStarted: parent.flickableDirection = Flickable.HorizontalFlickonMovementEnded: parent.flickableDirection = Flickable.AutoFlickDirection}
} 
3. 下拉刷新实现
qml
Flickable {id: flickonMovementEnded: {if (contentY < -refreshThreshold) {// 触发刷新}}Rectangle {// 刷新指示器y: -heightvisible: flick.contentY < 0}
} 
性能优化技巧
-  
启用裁剪:
qml
Flickable {clip: true } -  
动态加载内容:
qml
Flickable {// 只加载可视区域内容Loader {visible: y >= flick.contentY && y <= flick.contentY + flick.height} } -  
减少过度绘制:
qml
Flickable {layer.enabled: truelayer.textureSize: Qt.size(width, height) }