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

news2025/1/17 23:01:28

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

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

1.SmoothStackedWidget类实现

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

(支持快滑,慢滑)

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

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

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

2.代码实现

头文件如下所示:

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

#ifndef SMOOTHSTACKEDWIDGET_H
#define SMOOTHSTACKEDWIDGET_H

#include <QObject>
#include <QWidget>
#include <QStackedWidget>
#include <QAbstractScrollArea>
#include <QPixmap>
#include <QPropertyAnimation>

class SmoothStackedWidget : public QStackedWidget
{
    Q_OBJECT

#define SMOOTH_MAX_MS   900                   //平滑滑动时的最大延迟时间
#define SMOOTH_EDGE_MOVE_RATIO   0.14         //边缘移动系数,范围0~1,越低越慢

    typedef enum tagScrollMouseDragInfo {
          MOUSE_RELEASE = 0,                       //鼠标离开
          MOUSE_PRESS = 1,                         //按下
          MOUSE_PRESS_MOVE = 2,                    //按下移动
          MOUSE_RELEASE_MOVE = 3                   //鼠标离开并滑动
    }Scroll_Mouse_Drag_INFO_E;

    typedef enum tagSmoothAnimationSwitchInfo {
          SWITCH_PRE = -1,                      //切换上一页
          SWITCH_NONE = 0,                      //不切换
          SWITCH_NEXT = 1,                      //切换下一页
    }AnimationSwitch_Drag_INFO_E;

    Scroll_Mouse_Drag_INFO_E m_dragFlag = MOUSE_RELEASE;
    AnimationSwitch_Drag_INFO_E m_switchFlag = SWITCH_NONE;
  
    QWidget *m_parent;

    QWidget m_smoothWidget;

    int m_smoothCurrentIndex=-1;

    QPropertyAnimation *animation;

    float m_smoothMovePos;

    bool eventFilter(QObject *obj, QEvent *evt) override;

    void paintEvent(QPaintEvent *event) override;

    void resizeEvent(QResizeEvent *event) override;

    void SmoothLoadPixmap(bool isSmoothUpdate = false);
    void SmoothStartMove();

    void SmoothMove(int offset);

    void SmoothAnimationStart(int startPos, int endPos, int durationMs);

    void SmoothAnimationInit();

public:
    explicit SmoothStackedWidget(QWidget *parent = nullptr);

    int addWidget(QAbstractScrollArea *w);

    int addWidget(QWidget *w);

    void setCurrentIndex(int index);

    void removeWidget(QWidget *w);

    void IconUpdate();      //刷新页数标签

    void UpdateSmooth();

signals:

protected slots:
    void OnSmoothAnimationFinished();

};

#endif // SMOOTHSTACKEDWIDGET_H

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

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

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

bool SmoothStackedWidget::eventFilter(QObject *obj, QEvent *evt)
{
    QMouseEvent *mouse =  dynamic_cast<QMouseEvent *>(evt);
    QWidget *w =  dynamic_cast<QWidget *>(obj);

    static int pressPoint_x   = 0;          //按下的坐标
    static int dragPoint_x    = -1;         //拖动时的坐标
    static qint64 pressMSec ;

    if(mouse && w && animation->state() == QAbstractAnimation::Stopped)
    {
         if( mouse->type() ==QEvent::MouseButtonPress)    //首次按下
        {
           pressMSec = QDateTime::currentDateTime().toMSecsSinceEpoch();     //记录按下的时间
           dragPoint_x  = mouse->pos().x();               //当前坐标
           pressPoint_x = dragPoint_x;                    //按下的位置
           m_dragFlag = MOUSE_PRESS;
        }
         else if(mouse->type() == QEvent::MouseButtonRelease &&
                 m_dragFlag == MOUSE_PRESS)               //未移动
        {
           m_dragFlag = MOUSE_RELEASE;
        }
         else if(mouse->type() == QEvent::MouseMove &&
                 m_dragFlag == MOUSE_PRESS)               //初次滑动,判断移动阀值,避免误操作
        {
            if(qAbs(dragPoint_x - mouse->pos().x()) > 3)     //判断移动阀值,避免误操作
            {
               dragPoint_x = mouse->pos().x();
               SmoothStartMove();
               m_dragFlag = MOUSE_PRESS_MOVE;
            }
        }
         else if(mouse->type() == QEvent::MouseMove &&
                 m_dragFlag== MOUSE_PRESS_MOVE )             //正在滑动
        {
            int offset = ( mouse->pos().x() - dragPoint_x);
            SmoothMove(offset);
            dragPoint_x = mouse->pos().x();
        }
        else if(mouse->type() == QEvent::MouseButtonRelease &&
                m_dragFlag == MOUSE_PRESS_MOVE)               //滑动结束,启动平滑滑动
        {
             int durationMs= QDateTime::currentDateTime().toMSecsSinceEpoch()-pressMSec;
             SmoothAnimationStart(pressPoint_x,mouse->pos().x(),durationMs);
             m_dragFlag = MOUSE_RELEASE;
        }
    }

    return QWidget::eventFilter(obj,evt);
}

SmoothAnimationStart()函数如下所示:

void  SmoothStackedWidget::SmoothAnimationStart(int startPos, int endPos, int durationMs)
{
    int pixelPerSecond=qAbs(endPos - startPos)*1000/durationMs;       //计算每秒像素点
    m_switchFlag = SWITCH_NONE;
    int moveX = qAbs(m_smoothWidget.x());
    float temp = width()*0.5;
    int animationEndX;

    //慢速滑动(速度过慢||时间过长),则根据当前滑到哪里,就跳到哪里
    if(pixelPerSecond<300 || durationMs > 1000) {
        if(moveX < (temp)) {        //[0,width/2] = 上一页
            if(currentIndex()==0) {
                animationEndX = -width();
            } else {
                animationEndX = 0;
                m_switchFlag = SWITCH_PRE;
            }
        } else if(moveX < (temp*3)) {    //[width/2,width*3/2] = 当前一页
            animationEndX = -width();
        } else {
            if(currentIndex()==(count()-1)) {   //[width*3/2,width*2] = 下一页
                animationEndX = -width();
            } else {
                animationEndX = -width()*2;
                m_switchFlag = SWITCH_NEXT;
            }
        }

    } else {    // 否则就是快速滑动
        if(startPos < endPos) { //向右滑动
            if(currentIndex()==0) {
                animationEndX = -width();
            } else {
                animationEndX = 0;
                m_switchFlag = SWITCH_PRE;
            }
        } else {         //向左滑动
            if(currentIndex()==(count()-1)) {
                animationEndX = -width();
            } else {
                animationEndX = -width()*2;
                m_switchFlag = SWITCH_NEXT;
            }
        }
    }

    //根据每秒滑动像素点,来计算滑动时长.
    int animationDuration = durationMs;
    float xOffsetRatio = qAbs(animationEndX - m_smoothWidget.x()) / (static_cast<float>(width())); //计算滑动占整屏比例

    if(animationDuration > (SMOOTH_MAX_MS * xOffsetRatio)) //滑动时间过大,则重置
        animationDuration = SMOOTH_MAX_MS * xOffsetRatio;


    animation->setDuration(animationDuration);
    animation->setStartValue(m_smoothWidget.geometry());
    animation->setEndValue(QRect(animationEndX, m_smoothWidget.y(), m_smoothWidget.width(), m_smoothWidget.height()));
    animation->start();
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/44601.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]计算机毕业设计springboot第三方游戏零售平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Discourse 在 2022-11 的最新版本中提供了新的边栏

官方有关这个边栏的说明和解释文章请参考链接&#xff1a; Try out the new sidebar and notification menus! - announcements - Discourse Meta 中的内容。 在这个新设计的边栏中包含了一些所有人都需要使用的快捷链接&#xff0c;同时还包括一些定义的快捷分类链接和 Tag 链…

haproxy keepalive实践

1 安装haproxy wget http://download.openpkg.org/components/cache/haproxy/haproxy-2.6.6.tar.gz tar -zxvf haproxy-2.6.6.tar.gz cd haproxy-2.6.6 mkdir -p /app/haproxy # 安装依赖,解决haproxy.c:80:31的问题 sudo yum -y install gcc openssl-devel pcre-devel system…

【Python】一、Python程序运行方式

文章目录实验目的一、熟悉Python的安装二、熟悉PyCharm安装三、启动IDLE&#xff0c;进入Python Shell&#xff0c;熟悉环境&#xff0c;运行教材案例&#xff1a;输出“hello world&#xff01;”四、打开“命令提示符”窗口&#xff0c;使用pip安装管理pygame、numpy等第三方…

算法训练Day30 回溯算法专题 | LeetCode332. 重新安排行程;51.N皇后(棋盘问题);37.解数独(二维的递归)

前言&#xff1a; 算法训练系列是做《代码随想录》一刷&#xff0c;个人的学习笔记和详细的解题思路&#xff0c;总共会有60篇博客来记录&#xff0c;计划用60天的时间刷完。 内容包括了面试常见的10类题目&#xff0c;分别是&#xff1a;数组&#xff0c;链表&#xff0c;哈…

android 自定义view: 跑马灯-光圈

本系列自定义View全部采用kt **系统: **mac android studio: 4.1.3 **kotlin version:**1.5.0 gradle: gradle-6.5-bin.zip 本篇效果: 前沿 最近在bilibili看到一个跑马灯光圈效果挺好, 参考着思路写了一下. bilibili地址,美中不足的是这是html代码 QaQ 实现思路 将效果…

Spark系列之Spark启动与基础使用

title: Spark系列 第三章 Spark启动与基础使用 3.1 Spark Shell 3.1.1 Spark Shell启动 安装目录的bin目录下面&#xff0c;启动命令&#xff1a; spark-shell$SPARK_HOME/bin/spark-shell \ --master spark://hadoop10:7077 \ --executor-memory 512M \ --total-executor-…

长短期记忆网络(LSTM)重点!(自己汇集了很多资料在这篇博客)

文章目录参考资料推荐基础知识评论区精髓代码实现底层实现简洁实现参考资料推荐 心心念念 学了这么久 &#xff0c;终于学到第57集了。 参考一篇掘金的图文LSTM 李宏毅老师的手撕视频配套课件 27:39 开始手撕 看完了李沐老师的LSTM又去找了李宏毅老师的课程然后发现又多了个导…

西门子机床联网

一、设备信息确认 1、确认型号 数控面板拍照确认&#xff1a; 此系统为&#xff1a;西门子828D 还有一种情况是面板无任何版本信息&#xff0c;这时就需要进入系统里面再确认。 2、确认通讯接口 1、数控面板的后面 X130为网络标号 2、其他位置 其他位置一般是前面位置用…

H3C mstp+vrrp实验 新华三杯拆解

H3C mstpvrrp实验一、实验拓扑二、实验要求局域网规划&#xff1a;可靠性&#xff1a;三、实验配置&#xff08;一&#xff09;链路聚合1.创建链路聚合组2.检查&#xff08;二&#xff09;VLAN1.创建vlan2.放行vlan3.检查&#xff08;三&#xff09;MSTP1.配置MSTP域2.配置主备…

通俗易懂的java设计模式(1)-单例模式

什么是单例模式&#xff1f; 单例模式是java中最简单的一种设计模式 需要注意的问题&#xff1a; 1.单例类有且只能有一个实例 2.单例类必须自己创建出这个实例&#xff0c;并提供给外界 那么如何自己创建实例而不让外界创建呢&#xff1f;很简单&#xff0c;我们将无参的构造函…

麦芽糖-刀豆球蛋白A,maltose-ConcanavalinA,刀豆球蛋白A-PEG-麦芽糖

麦芽糖-刀豆球蛋白A,maltose-ConcanavalinA,刀豆球蛋白A-PEG-麦芽糖 中文名称&#xff1a;麦芽糖-刀豆球蛋白A 英文名称&#xff1a;maltose-ConcanavalinA 别称&#xff1a;刀豆球蛋白A修饰麦芽糖&#xff0c;ConA-麦芽糖 还可以提供PEG接枝修饰麦芽糖&#xff0c;麦芽糖…

SpringCloud-alibaba-Nacos 从理论到落地使用

Nacos: Dynamic Naming and Configuration Service 就是&#xff1a; 一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。、 下面是生态图&#xff1a; Nacos EurekaConfig Bus 即 Nacos就是注册中心 配置中心的组合 他能干什么呢&#xff1f; 1、替代Eu…

防火墙firewalld

RHEL7中有几种防火墙共存&#xff1a;firewalld、iptables、ebtables等。基于iptables的防火墙默认不启动&#xff0c;但仍然可以继续使用。RHEL7默认使用firewalld作为防火墙&#xff0c;管理工具是firewall-cmd。RHEL7的内核版本是3.10&#xff0c;在此版本的内核里防火墙的包…

论文阅读2 Learning Hierarchy-Aware Knowledge Graph Embeddings for Link Prediction

目录 问题 创新 1、Introduction 2、相关工作 3、HAKE模型 原文&#xff1a;[1911.09419] Learning Hierarchy-Aware Knowledge Graph Embeddings for Link Prediction (arxiv.org) 问题 现有的知识图嵌入模型主要关注对称/反对称、反转和复合symmetry/antisymmetry, i…

EquiVSet

又搬来一个于最优子集的神经集合函数学习方法 集合函数被广泛应用于各种场景之中&#xff0c;例如商品推荐、异常检测和分子筛选等。在这些场景中&#xff0c;集合函数可以被视为一个评分函数&#xff1a;其将一个集合作为输入并输出该集合的分数。我们希望从给定的集合中选取…

【新知实验室-TRTC开发】实时音视频之欢度世界杯

目录 一、什么是TRTC 二、用5分钟跑通一个demo 1、开通腾讯云-TRTC 2、获取demo必须的两把钥匙 2.1输入应用名称 2.2下载对应的源码包&#xff08;手机、web、小程序等&#xff09; 2.3拿到钥匙 2.4完成 三、搭建一起看世界杯应用 1、解压源码&#xff08;耗时30S&#x…

Linux下top命令详解

Linux下top命令用法详解 作为一名Linux软件攻城狮&#xff0c;top命令大家应该并不陌生。top命令是Linux下常用的性能分析工具&#xff0c;能够实时显示系统中各个进程的资源占用状况。top可以动态显示过程,不断刷新当前状态。top命令提供了实时的对系统处理器的状态监视。它将…

Kotlin高仿微信-第5篇-主页-通讯录

Kotlin高仿微信-项目实践58篇详细讲解了各个功能点&#xff0c;包括&#xff1a;注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。 Kotlin高仿…

【博客547】keepalived实现vip的原理剖析

keepalived实现vip的原理剖析 keepalived实现vip的原理&#xff1a;vrrp gratuitous arp 1、vrrp vrrp更多细节参考&#xff1a;vrrp技术白皮书 相关术语&#xff1a; VRRP工作过程 VRRP的工作过程为&#xff1a; 1、虚拟路由器中的路由器根据优先级选举出Master。Master…