Qt关于平滑滚动的使用QScroller及QScrollerProperties类说明

embedded/2025/3/1 11:34:52/

一、触控时代的滚动工具:QScroller类设计介绍

1.1 从机械滚轮到数字惯性

在触控设备普及前,滚动操作如同老式打字机的滚轴,只能通过鼠标滚轮或滚动条进行离散式控制。QScroller的出现如同给数字界面装上了"惯性飞轮",通过模拟物理上的动量守恒定律,让滚动操作具备以下特性:

  • 速度传递:滑动速度决定滚动距离;
  • 动态衰减:摩擦系数影响停止时间;
  • 边界弹性:类似橡皮筋的越界回弹效果;

1.2 类关系拓扑图

QScroller ────┬── QScrollerProperties ├── QScrollEvent └── QScrollPrepareEvent 

QScroller作为控制器,通过QScrollerProperties配置物理参数,生成QScrollEvent事件以驱动界面的刷新。

二、核心类深度解析

2.1 QScroller类:滚动引擎

关键方法说明:

// 启用控件手势支持(核心入口)
static QScroller *QScroller::grabGesture(QObject *target, QScroller::GestureType gestureType = TouchGesture 
);//检查指定的目标对象是否已经关联了 QScroller 实例
static bool hasScroller(QObject *target) ;//使指定的目标对象停止捕获指定类型的滚动手势
static void ungrabGesture(QObject *target, 
QScroller::ScrollerGestureType gestureType);// 获取当前滚动状态 
QScroller::State state() const; // 滚动到指定区域(带动画)
void scrollTo(const QVector2D &pos, qreal scrollTime = 0);// 确保子控件可见(自动计算滚动路径)
void ensureVisible(const QRectF &rect, qreal xmargin = 0.1, qreal ymargin = 0.1);//设置滚动器的属性,如滚动速度、摩擦力、弹性等
void setScrollerProperties(const QScrollerProperties &properties);//启动滚动器,开始滚动操作
void start();//停止滚动器,终止滚动操作
void stop();//设置水平方向的捕捉位置。当滚动到这些位置时,滚动器会自动对齐到这些位置。
void setSnapPositionsX(const QList<qreal> &positions);//设置垂直方向的捕捉位置。当滚动到这些位置时,滚动器会自动对齐到这些位置。
void setSnapPositionsY(const QList<qreal> &positions);

手势类型枚举:

enum GestureType {TouchGesture,        // 触摸手势 LeftMouseButtonGesture, // 左键拖拽RightMouseButtonGesture // 右键拖拽(特殊场景)
};

2.2 QScrollerProperties:设置和调整配置参数

这个类就像汽车的"悬挂调校系统"调节汽车引擎一样,专门调整设置QScroller类的配置参数,包含几十个可配置参数,主要有:

QScrollerProperties properties;//设置滚轮滚动过程中画面的帧率,帧率越高看着越舒服,帧率越低画面越跳动
properties.setScrollMetric(QScrollerProperties::FrameRate,QScrollerProperties::Fps30);
//设置平滑速度,当滑动完手离开屏幕后,进行平滑滑动的速度,此值应介于0和1之间。值越小,速度越慢。但我试过实际没太明显的区别
properties.setScrollMetric(QScrollerProperties::DragVelocitySmoothingFactor,0.3);
//设置鼠标释放后滚动到停止时的运动曲线,参数为QEasingCurve类型,不能设置为QEasingCurve::Type类型,不会隐式转换
properties.setScrollMetric(QScrollerProperties::ScrollingCurve,QEasingCurve::OutQuad);
//设置移动阀值(按下后需要移动最少距离后,触发滑动),用来避免误操作
properties.setScrollMetric(QScrollerProperties::DragStartDistance,0.003);
//设置减速因子,值越大,减速越快,进而会影响点击释放后滚动的距离。对于大多数类型,该值应在0.1到2.0的范围内
properties.setScrollMetric(QScrollerProperties::DecelerationFactor,0.4);
//设置当运动方向与某一个轴的角度小于该设定值(0~1)时,则限定只有该轴方向的滚动,一般就用0.5,两个轴都是,不然要么区域重叠,要么区域漏掉
properties.setScrollMetric(QScrollerProperties::AxisLockThreshold,0.5);
//自动滚动过程中,鼠标点击操作会停止当前滚动,当速度大于该设定(m/s)时,鼠标事件不会传递给目标即不会停止滚动
properties.setScrollMetric(QScrollerProperties::MaximumClickThroughVelocity,0.5);
//与AcceleratingFlickSpeedupFactor配合使用。设置时间及加速因子
properties.setScrollMetric(QScrollerProperties::AcceleratingFlickMaximumTime ,3);
//与AcceleratingFlickMaximumTime配合使用,应>=1
properties.setScrollMetric(QScrollerProperties::AcceleratingFlickSpeedupFactor,2);
//设置自动滑动的最小速度,m/s,如果手势的速度小于该速度,则不会触发自动滚动,所以可以设置得小一些,防止手指轻微移动引起屏幕滚动
properties.setScrollMetric(QScrollerProperties::MinimumVelocity,0.2);
//设置自动滚动能达到得最大速度,m/s
properties.setScrollMetric(QScrollerProperties::MaximumVelocity,0.2);
//设置当拖拽过量时,释放后位置恢复所用时间(s)
properties.setScrollMetric(QScrollerProperties::OvershootScrollTime,0.2);
//设置滚动曲线的时间因子。设置滚动的时长,值越小,滚动时间越长
properties.setScrollMetric(QScrollerProperties::SnapTime,0.2);
//设置过量拖拽的距离占页面的比例,0~1,比如设置0.2,过量拖拽垂直最多移动高度的1/5
properties.setScrollMetric(QScrollerProperties::OvershootDragDistanceFactor,0.2);
//设置垂直向允许过量拖拽的策略,可以设置滚动条出现时开启、始终关闭、始终开启三种策略
properties.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy,QScrollerProperties::OvershootWhenScrollable);
//设置过量拖拽的移动距离与鼠标移动距离的比例,0~1,值越小表现出的阻塞感越强
properties.setScrollMetric(QScrollerProperties::OvershootDragResistanceFactor,0.2);
//设置自动滚动时允许的过量滚动距离比例
properties.setScrollMetric(QScrollerProperties::OvershootScrollDistanceFactor,0.2);
//设置鼠标事件延迟时间,单位s。
properties.setScrollMetric(QScrollerProperties::MousePressEventDelay,1);QScroller::scroller(ui->scrollArea)->setScrollerProperties(properties);

三、实现原理揭秘

3.1 事件处理流水线

sequenceDiagram participant User participant QScroller participant Widget User->>QScroller: 触摸/鼠标按下 QScroller->>Widget: 发送ScrollPrepare事件 Widget->>QScroller: 返回内容尺寸等信息 loop 每帧更新 QScroller->>QScroller: 计算物理运动参数 QScroller->>Widget: 发送ScrollEvent Widget->>Widget: 更新显示位置 end User->>QScroller: 释放操作 QScroller->>Widget: 触发惯性滚动 

3.2 物理模型公式

滚动位置计算采用改进型牛顿运动方程:

当前位置 = 初始位置 + 初速度 * t - 0.5 * 摩擦系数 * t²

其中摩擦系数通过QScrollerProperties::DecelerationFactor动态调整


四、实用代码示例

4.1 基础滑动实现

// 为QListWidget启用触控滑动 
QListWidget *list = new QListWidget(this);
QScroller *scroller = QScroller::scroller(list->viewport());
QScroller::grabGesture(list->viewport(), QScroller::TouchGesture);// 配置滑动参数(类似手机APP的流畅感)
QScrollerProperties prop = scroller->scrollerProperties();
prop.setScrollMetric(QScrollerProperties::DragVelocitySmoothingFactor,  0.6);
prop.setScrollMetric(QScrollerProperties::OvershootScrollDistanceFactor,  0.3);
scroller->setScrollerProperties(prop);

4.2 高级分页滚动

// 相册浏览分页效果 
QScrollArea *gallery = new QScrollArea(this);
QScroller::grabGesture(gallery, QScroller::LeftMouseButtonGesture);QScrollerProperties prop;
prop.setScrollMetric(QScrollerProperties::SnapPositionRatio,  1.0); // 整页吸附 
prop.setScrollMetric(QScrollerProperties::SnapTime,  0.5);         // 过渡动画时长 
QScroller::scroller(gallery)->setScrollerProperties(prop);

五、性能优化指南

  1. 渲染优化
// 启用像素级滚动(避免跳跃感)
listWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
  1. 内存管理
// 及时释放不再使用的滚动器
QScroller::ungrabGesture(scrollArea); // 类似断开刹车系统
  1. 动态调参技巧
// 根据设备类型切换参数 
#ifdef Q_OS_ANDROID prop.setScrollMetric(...);  // 移动端优化参数 
#else prop.setScrollMetric(...);  // 桌面端参数 
#endif 

结语:滚动交互的未来

随着Qt6对QScroller的持续优化,已经未来产品更趋向于实际流畅感的需求,作为开发使用人员,这几个方面的优化值得我们关注使用:

  1. 多指操作与3D滚动集成
  2. 基于AI的动态参数调优
  3. 与Vulkan渲染引擎的深度结合


http://www.ppmy.cn/embedded/169041.html

相关文章

软件高级架构师 - 设计模式

六大原则 1. 单一职责原则 一个类只负责一项职责。 案例 餐厅中的厨师和服务员&#xff1a; 厨师的职责是做饭&#xff0c;服务员的职责是上菜。 如果让厨师同时负责做饭和上菜&#xff0c;会导致职责混乱&#xff0c;效率降低。 2. 开放-封闭原则&#xff08;OCP&#xff09…

配置Spring Boot中的Jackson序列化

配置Spring Boot中的Jackson序列化 在开发基于Spring Boot的应用程序时&#xff0c;Jackson是默认的JSON序列化和反序列化工具。它提供了强大的功能&#xff0c;可以灵活地处理JSON数据。然而&#xff0c;Jackson的默认行为可能无法完全满足我们的需求。例如&#xff0c;日期格…

React antd的datePicker自定义,封装成组件

一、antd的datePicker自定义 需求&#xff1a;用户需要为日期选择器的每个日期单元格添加一个Tooltip&#xff0c;当鼠标悬停时显示日期、可兑换流量余额和本公会可兑流量。这些数据需要从接口获取。我需要结合之前的代码&#xff0c;确保Tooltip正确显示&#xff0c;并且数据…

【Prometheus】prometheus服务发现与relabel原理解析与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…

Android实现漂亮的波纹动画

Android实现漂亮的波纹动画 本文章讲述如何使用二维画布canvas和camera、矩阵实现二、三维波纹动画效果&#xff08;波纹大小变化、画笔透明度变化、画笔粗细变化&#xff09; 一、UI界面 界面主要分为三部分 第一部分&#xff1a;输入框&#xff0c;根据输入x轴、Y轴、Z轴倾…

【MySQL】数据库开发技术:内外连接与表的索引穿透深度解析

**前言:**本节内容主要讲解表的内连和外连以及索引的一部分。 注意&#xff1a; 索引是很重要的知识点。务必学习&#xff01;&#xff01;本节将会主要谈一谈什么是索引&#xff0c;如何理解索引。 以及怎么理解MySQL与磁盘的关系。 下面友友们开始学习吧&#xff01; ps&…

【北京迅为】iTOP-RK3568OpenHarmony系统南向驱动开发-第2章 内核HDF驱动框架架构

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

自动化测试无法启动(java.net.SocketException)

在运行测试代码,对浏览器进行自动化操作时,遇到了以下问题,添加依赖,编写了测试代码,但是程序无法运行 这个有两种原因(我使用的是谷歌浏览器): 网络问题: 因为需要从GitHub上下载对应包,所以有时候可能会出现网络问题,这个时候可以打开VPN之后,重新对程序进行启动 浏览器版本…