• QT开发教程:QScroller实现home界面滑动效果


    在上章我们学习了QScroller实现home界面滑动效果,但是该界面是实现的上下滑动效果,如果想模拟手机home滑动界面,则需要实现左右滑动效果.

    本章,则重写QStackedWidget类,来真正的模拟手机,来实现home界面左右滑动效果.

    1.SmoothStackedWidget类实现

    demo界面如下图所示(创建了4个子界面):

    (支持快滑,慢滑)

    如果是慢滑,则根据当前滑到的界面处于哪一页占比更多,则就跳到哪里.

    否则就是快滑,根据滑动的偏移值来决定跳转

    同样也支持边缘滑动检测(已在最边缘时,则滑动速率减慢,告诉用户已到边缘)

    2.代码实现

    头文件如下所示:

    本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

    1. #ifndef SMOOTHSTACKEDWIDGET_H
    2. #define SMOOTHSTACKEDWIDGET_H
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. class SmoothStackedWidget : public QStackedWidget
    10. {
    11. Q_OBJECT
    12. #define SMOOTH_MAX_MS 900 //平滑滑动时的最大延迟时间
    13. #define SMOOTH_EDGE_MOVE_RATIO 0.14 //边缘移动系数,范围0~1,越低越慢
    14. typedef enum tagScrollMouseDragInfo {
    15. MOUSE_RELEASE = 0, //鼠标离开
    16. MOUSE_PRESS = 1, //按下
    17. MOUSE_PRESS_MOVE = 2, //按下移动
    18. MOUSE_RELEASE_MOVE = 3 //鼠标离开并滑动
    19. }Scroll_Mouse_Drag_INFO_E;
    20. typedef enum tagSmoothAnimationSwitchInfo {
    21. SWITCH_PRE = -1, //切换上一页
    22. SWITCH_NONE = 0, //不切换
    23. SWITCH_NEXT = 1, //切换下一页
    24. }AnimationSwitch_Drag_INFO_E;
    25. Scroll_Mouse_Drag_INFO_E m_dragFlag = MOUSE_RELEASE;
    26. AnimationSwitch_Drag_INFO_E m_switchFlag = SWITCH_NONE;
    27. QWidget *m_parent;
    28. QWidget m_smoothWidget;
    29. int m_smoothCurrentIndex=-1;
    30. QPropertyAnimation *animation;
    31. float m_smoothMovePos;
    32. bool eventFilter(QObject *obj, QEvent *evt) override;
    33. void paintEvent(QPaintEvent *event) override;
    34. void resizeEvent(QResizeEvent *event) override;
    35. void SmoothLoadPixmap(bool isSmoothUpdate = false);
    36. void SmoothStartMove();
    37. void SmoothMove(int offset);
    38. void SmoothAnimationStart(int startPos, int endPos, int durationMs);
    39. void SmoothAnimationInit();
    40. public:
    41. explicit SmoothStackedWidget(QWidget *parent = nullptr);
    42. int addWidget(QAbstractScrollArea *w);
    43. int addWidget(QWidget *w);
    44. void setCurrentIndex(int index);
    45. void removeWidget(QWidget *w);
    46. void IconUpdate(); //刷新页数标签
    47. void UpdateSmooth();
    48. signals:
    49. protected slots:
    50. void OnSmoothAnimationFinished();
    51. };
    52. #endif // SMOOTHSTACKEDWIDGET_H

    其中eventFilter()函数如下所示:

    当鼠标(手指)按下移动时,则调用SmoothMove(offset),通过offset来动态显示滑动的界面.

    当鼠标(手指)松开后,则调用SmoothAnimationStart()来实现界面移动(到底是切换上一页、还是切换下一页、还是当前页).

    1. bool SmoothStackedWidget::eventFilter(QObject *obj, QEvent *evt)
    2. {
    3. QMouseEvent *mouse = dynamic_cast<QMouseEvent *>(evt);
    4. QWidget *w = dynamic_cast<QWidget *>(obj);
    5. static int pressPoint_x = 0; //按下的坐标
    6. static int dragPoint_x = -1; //拖动时的坐标
    7. static qint64 pressMSec ;
    8. if(mouse && w && animation->state() == QAbstractAnimation::Stopped)
    9. {
    10. if( mouse->type() ==QEvent::MouseButtonPress) //首次按下
    11. {
    12. pressMSec = QDateTime::currentDateTime().toMSecsSinceEpoch(); //记录按下的时间
    13. dragPoint_x = mouse->pos().x(); //当前坐标
    14. pressPoint_x = dragPoint_x; //按下的位置
    15. m_dragFlag = MOUSE_PRESS;
    16. }
    17. else if(mouse->type() == QEvent::MouseButtonRelease &&
    18. m_dragFlag == MOUSE_PRESS) //未移动
    19. {
    20. m_dragFlag = MOUSE_RELEASE;
    21. }
    22. else if(mouse->type() == QEvent::MouseMove &&
    23. m_dragFlag == MOUSE_PRESS) //初次滑动,判断移动阀值,避免误操作
    24. {
    25. if(qAbs(dragPoint_x - mouse->pos().x()) > 3) //判断移动阀值,避免误操作
    26. {
    27. dragPoint_x = mouse->pos().x();
    28. SmoothStartMove();
    29. m_dragFlag = MOUSE_PRESS_MOVE;
    30. }
    31. }
    32. else if(mouse->type() == QEvent::MouseMove &&
    33. m_dragFlag== MOUSE_PRESS_MOVE ) //正在滑动
    34. {
    35. int offset = ( mouse->pos().x() - dragPoint_x);
    36. SmoothMove(offset);
    37. dragPoint_x = mouse->pos().x();
    38. }
    39. else if(mouse->type() == QEvent::MouseButtonRelease &&
    40. m_dragFlag == MOUSE_PRESS_MOVE) //滑动结束,启动平滑滑动
    41. {
    42. int durationMs= QDateTime::currentDateTime().toMSecsSinceEpoch()-pressMSec;
    43. SmoothAnimationStart(pressPoint_x,mouse->pos().x(),durationMs);
    44. m_dragFlag = MOUSE_RELEASE;
    45. }
    46. }
    47. return QWidget::eventFilter(obj,evt);
    48. }

    SmoothAnimationStart()函数如下所示:

    1. void SmoothStackedWidget::SmoothAnimationStart(int startPos, int endPos, int durationMs)
    2. {
    3. int pixelPerSecond=qAbs(endPos - startPos)*1000/durationMs; //计算每秒像素点
    4. m_switchFlag = SWITCH_NONE;
    5. int moveX = qAbs(m_smoothWidget.x());
    6. float temp = width()*0.5;
    7. int animationEndX;
    8. //慢速滑动(速度过慢||时间过长),则根据当前滑到哪里,就跳到哪里
    9. if(pixelPerSecond<300 || durationMs > 1000) {
    10. if(moveX < (temp)) { //[0,width/2] = 上一页
    11. if(currentIndex()==0) {
    12. animationEndX = -width();
    13. } else {
    14. animationEndX = 0;
    15. m_switchFlag = SWITCH_PRE;
    16. }
    17. } else if(moveX < (temp*3)) { //[width/2,width*3/2] = 当前一页
    18. animationEndX = -width();
    19. } else {
    20. if(currentIndex()==(count()-1)) { //[width*3/2,width*2] = 下一页
    21. animationEndX = -width();
    22. } else {
    23. animationEndX = -width()*2;
    24. m_switchFlag = SWITCH_NEXT;
    25. }
    26. }
    27. } else {    // 否则就是快速滑动
    28. if(startPos < endPos) { //向右滑动
    29. if(currentIndex()==0) {
    30. animationEndX = -width();
    31. } else {
    32. animationEndX = 0;
    33. m_switchFlag = SWITCH_PRE;
    34. }
    35. } else { //向左滑动
    36. if(currentIndex()==(count()-1)) {
    37. animationEndX = -width();
    38. } else {
    39. animationEndX = -width()*2;
    40. m_switchFlag = SWITCH_NEXT;
    41. }
    42. }
    43. }
    44. //根据每秒滑动像素点,来计算滑动时长.
    45. int animationDuration = durationMs;
    46. float xOffsetRatio = qAbs(animationEndX - m_smoothWidget.x()) / (static_cast<float>(width())); //计算滑动占整屏比例
    47. if(animationDuration > (SMOOTH_MAX_MS * xOffsetRatio)) //滑动时间过大,则重置
    48. animationDuration = SMOOTH_MAX_MS * xOffsetRatio;
    49. animation->setDuration(animationDuration);
    50. animation->setStartValue(m_smoothWidget.geometry());
    51. animation->setEndValue(QRect(animationEndX, m_smoothWidget.y(), m_smoothWidget.width(), m_smoothWidget.height()));
    52. animation->start();
    53. }

    本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

  • 相关阅读:
    Go 定时任务执行-cron
    基于 Debian 稳定分支发行版的Zephix 7 发布
    Selenium自动化测试框架
    JS手写数组扁平化(flat)方法
    8月19日PMP出成绩时间公布了!查询攻略请收好!
    VsCode开发Vue(开源框架使用ruoyi)
    数据结构题目收录(四)
    linux系统下,在vscode的命令行中调试python文件
    vue3使用swiper6.7.0写轮播图,按钮在轮播图外面
    Docker第一天作业
  • 原文地址:https://blog.csdn.net/m0_60259116/article/details/128087690