C++复刻:[滑动侧边栏]

简介: 滑动侧边栏

参考

Python版本:GitHub地址
B站主页

效果

滑动侧边栏.gif

实现

main.cpp

#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    widget w;
    w.show();
    return a.exec();
}

widget.h

widget.cpp

#include "widget.h"
#include "slidingSideWindow.h"
#include <QDebug>
widget::widget(QWidget *parent)
    : QWidget{parent}
{
    this->resize(800,600);
    this->setWindowFlag(Qt::WindowStaysOnTopHint);
    //线性渐变
    setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, "
                  "stop:0 #e60042, stop:0.05 #d40f52, stop:0.20 #c21d62, stop:0.31 #af2c72, "
                  "stop:0.45 #7958a3, stop:0.79 #8b4993, stop:0.86 #6667b3, stop:0.935 #5475c3);");
    auto pSideWindow=new SlidingSideWindow(this);
    pSideWindow->move(this->rect().center().x()-pSideWindow->width()/2,
                      this->rect().center().y()-pSideWindow->height()/2);
    qDebug()<<__FUNCTION__<<" :x ="<<this->rect().center().x()-pSideWindow->width()/2;
    qDebug()<<__FUNCTION__<<" :y ="<<this->rect().center().y()-pSideWindow->height()/2;
}

widget::~widget()
{

}

custombtn.h 自定义按钮

#ifndef CUSTOMBTN_H
#define CUSTOMBTN_H

#include <QFrame>
#include <QObject>
#include <QPushButton>
#include <QPropertyAnimation>
#include <QPainter>
#include <QPainterPath>

class customBtn : public QFrame
{
    Q_OBJECT
    /* 将m_color属性声明为可用于属性系统的属性。然后,提供了一个getColor函数作为该属性的读取器,
     * 以及一个setColor函数作为写入器。
     *  在setColor函数中,我们可以执行一些自定义逻辑,并在属性值发生变化时进行处理。 */
    Q_PROPERTY(QColor m_color READ getColor WRITE setColor)
    Q_PROPERTY(QSize m_size READ getSize WRITE setSize)
public:
    customBtn(QWidget *parent = nullptr, QString text = "", QString iconFile = "");
    ~customBtn();
    QColor getColor() const { return m_color; }
    void setColor(const QColor& color);
    QSize getSize() const { return m_size; }
    void setSize(const QSize& color);
    QPushButton *pushButton(){return m_pPushButtonRight;}
    int getWidth(){return this->width();}
    int getHeight(){return this->height();}
protected:
    void paintEvent(QPaintEvent *event) override;
    void enterEvent(QEvent *event) override ;
    void leaveEvent(QEvent *event) override ;
signals:
    void colorChanged();            //响应m_color属性动画
private slots:
    void updateColor();
private:
    QSize m_size;
    QColor  m_color;
    QString m_iconFile;
    QString m_btnText;
    QPropertyAnimation *m_pAnimation;  //属性动画
    QPushButton* m_pPushButtonIcon;
    QPushButton* m_pPushButtonRight;
    void initUI();
    void hoveringAnimation();           //鼠标悬停动画
};

#endif // CUSTOMBTN_H

custombtn.cpp 自定义按钮

#include "custombtn.h"
#include <QDebug>
customBtn::customBtn(QWidget *parent, QString text, QString iconFile)
    : QFrame(parent), m_color(QColor(255, 116, 0, 255)), m_iconFile(iconFile), m_btnText(text)
{
    this->initUI();
}

customBtn::~customBtn()
{

}

void customBtn::setColor(const QColor &color)
{
    if (m_color != color) {
        m_color = color;
        emit colorChanged();
    }
}

void customBtn::setSize(const QSize &size)
{
    if (m_size != size) {
        m_size = size;
        this->resize(size);
    }
}

void customBtn::hoveringAnimation()
{
    m_pAnimation->setTargetObject(this);        //动画的目标对象设置为当前对象
    m_pAnimation->setPropertyName("m_color");   //动画关联到属性m_color,这意味着动画将修改该属性的值来实现动画效果
    m_pAnimation->setDuration(300);             //动画的持续时间
    //动画的开始值和结束值
    m_pAnimation->setStartValue(QColor(255, 116, 0, 255));
    m_pAnimation->setEndValue(QColor(255, 116, 255, 225));
    m_pAnimation->start();
}

void customBtn::paintEvent(QPaintEvent *event)
{
    QFrame::paintEvent(event);

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing); // 抗锯齿
    //设置画笔; Qt::NoPen 表示不使用画笔,也就是不绘制边框
    painter.setPen(Qt::NoPen);

    // 绘制圆角矩形背景
    QPainterPath path;
    path.addRoundedRect(this->rect(), 10, 10);
    painter.fillPath(path, m_color);
}

void customBtn::enterEvent(QEvent *event)
{
    // 设置动画的方向为正向
    m_pAnimation->setDirection(QAbstractAnimation::Forward);
    hoveringAnimation();
    QFrame::enterEvent(event);
}

void customBtn::leaveEvent(QEvent *event)
{
    //将动画设置为反向播放
    m_pAnimation->setDirection(QAbstractAnimation::Backward);
    this->hoveringAnimation();
    QFrame::leaveEvent(event);
}

void customBtn::updateColor()
{
    //按钮的背景颜色需要设置成透明,以便于绘制显示QFrame底色
    this->setStyleSheet(QString("QFrame{border-radius: 10px; background-color: rgba(255, 116, 200, 225);} "
                          "QPushButton{border-radius: 10px; background-color: transparent; color: rgb(255, 255, 255);}"));
    this->update();
}

void customBtn::initUI()
{
    this->resize(110, 30);
    this->setMinimumSize(40, 30);
    this->setMaximumSize(110, 30);
    m_size=this->size();
    //QFrame背景颜色和按钮的背景颜色一样,这样就看不见两个按钮之间的边框圆角
    this->setStyleSheet(QString("QFrame{border-radius: 10px; background-color: rgba(255, 116, 0, 255); color: rgb(255, 255, 255);} "
                          "QPushButton{border-radius: 10px; background-color: rgba(255, 116, 0, 255); color: rgb(255, 255, 255);}"));
    m_pPushButtonIcon = new QPushButton(this);
    m_pPushButtonIcon->setGeometry(QRect(0, 0, 30, 31));
    m_pPushButtonIcon->setStyleSheet("padding-left:10px");//设置左边内边距的大小
    QIcon icon(m_iconFile);
    m_pPushButtonIcon->setIcon(icon);
    m_pPushButtonIcon->setIconSize(QSize(20, 20));

    m_pPushButtonRight = new QPushButton(this);
    m_pPushButtonRight->setGeometry(QRect(30, 0, 80, 31));
    m_pPushButtonRight->setStyleSheet("padding-left:15px; text-align: left;");
    m_pPushButtonRight->setIconSize(QSize(20, 20));
    m_pPushButtonRight->setText(m_btnText);
    m_pPushButtonRight->setCheckable(true);
    connect(this,SIGNAL(colorChanged()), this, SLOT(updateColor()));

    m_pAnimation=new QPropertyAnimation(this);
}

slidingSideWindow.h 滑动侧边栏

#ifndef SLIDINGSIDEWINDOW_H
#define SLIDINGSIDEWINDOW_H

#include <QFrame>
#include <QPropertyAnimation>
#include <QAbstractAnimation>
#include <QParallelAnimationGroup>
#include <QPushButton>
#include "custombtn.h"


class SlidingSideWindow : public QFrame
{
    Q_OBJECT

public:
    SlidingSideWindow(QWidget *parent = nullptr);
    ~SlidingSideWindow();
protected:
    void enterEvent(QEvent *event) override;
    void leaveEvent(QEvent *event) override;
private:
    int m_widthHide;                //滑动侧边栏隐藏时宽度
    int m_widthShow;                //滑动侧边栏显示时宽度
    int m_widthChange;              //变化使用宽度
    int m_xShow;
    int m_xHide;
    int m_y;
    int m_customBtn_widthShow;
    int m_customBtn_widthHide;
    int m_customBtn_height;
    bool enterFlag;                 // 判断是否第一次进入
    QParallelAnimationGroup *animationGroup;//并行播放多个动画的动画组
    void initUI();
    void configInit();
    void animationGroupConfig();
    void anewRecordPos();            //重新记录位置
};

#endif // SLIDINGSIDEWINDOW_H

slidingSideWindow.cpp 滑动侧边栏


#include "slidingSideWindow.h"
#include <QDebug>
SlidingSideWindow::SlidingSideWindow(QWidget *parent)
    : QFrame(parent)
{
    initUI();
    configInit();
}

SlidingSideWindow::~SlidingSideWindow()
{
}

void SlidingSideWindow::enterEvent(QEvent *event)
{
    QFrame::enterEvent(event);
    // 跳过第一次
    if (!enterFlag)
    {
        enterFlag = true;
        /*因为new时 this->x()和y() 都是0; move之后才有值;只记录第一次进入this的Pos()*/
        anewRecordPos();            //重新记录位置
        return;
    }

    // 显示包含文字的按钮
    QList<customBtn *> frames = this->findChildren<customBtn *>();
    for (auto item : frames)
    {
        item->pushButton()->show();
    }

    animationGroup->setDirection(QAbstractAnimation::Backward);
    animationGroup->start();
}

void SlidingSideWindow::leaveEvent(QEvent *event)
{
    QFrame::leaveEvent(event);
    QList<customBtn *> frames = this->findChildren<customBtn *>();
    for (auto item : frames)
    {
        item->pushButton()->hide();
    }

    animationGroup->setDirection(QAbstractAnimation::Forward);
    animationGroup->start();
}


void SlidingSideWindow::initUI()
{
    this->resize(141, 271);
    this->setStyleSheet("QFrame{border-radius: 15px;"
            "background-color: rgba(255, 116, 0,200);}");
    // 判断是否第一次进入
    enterFlag = false;

    //并行播放多个动画的动画组
    animationGroup = new QParallelAnimationGroup(this);
}

void SlidingSideWindow::configInit()
{
    auto childFrame =new customBtn(this,"Close",":/icon/Close.png");
    childFrame->setGeometry(QRect(10, 20, 110, 30));
    auto childFrame_2 =new customBtn(this,"Enter",":/icon/Enter.png");
    childFrame_2->setGeometry(QRect(10, 60, 110, 30));
    auto childFrame_3 =new customBtn(this,"SetKey",":/icon/SetKey.png");
    childFrame_3->setGeometry(QRect(10, 100, 110, 30));
    auto childFrame_4 =new customBtn(this,"Resign",":/icon/Resign.png");
    childFrame_4->setGeometry(QRect(10, 140, 110, 30));
    auto childFrame_5 =new customBtn(this,"Verify",":/icon/Verify.png");
    childFrame_5->setGeometry(QRect(10, 180, 110, 30));
    auto childFrame_6 =new customBtn(this,"Share",":/icon/Share.png");
    childFrame_6->setGeometry(QRect(10, 220, 110, 30));
    m_customBtn_widthShow = childFrame->getWidth();
    m_customBtn_widthHide = 40;
    m_customBtn_height = childFrame->getHeight();

    anewRecordPos();            //重新记录位置
}

void SlidingSideWindow::animationGroupConfig()
{
    // 清空动画组
    animationGroup->clear();

    /*在leaveEvent和enterEvent中对右侧按钮隐藏后,通过QPropertyAnimation属性动画修改customBtn的
     *自定义属性m_size,以更改customBtn底下的QFrame大小。否则QFrame存在background-color就看不到
     *customBtn图标的右侧圆角*/
    // 按钮动画
    QList<customBtn *> frames = this->findChildren<customBtn *>();
    for (auto childFrame : frames)
    {
        QPropertyAnimation *btnAnimation = new QPropertyAnimation(childFrame, "m_size");
        btnAnimation->setDuration(150);
        btnAnimation->setStartValue(QSize(m_customBtn_widthShow, m_customBtn_height));
        btnAnimation->setEndValue(QSize(m_customBtn_widthHide, m_customBtn_height));
        animationGroup->addAnimation(btnAnimation);      // 添加属性动画到动画组
    }

    // 侧边栏动画
    QPropertyAnimation *frameAnimation = new QPropertyAnimation(this, "geometry");
    frameAnimation->setDuration(150);
    frameAnimation->setStartValue(QRect(m_xShow, m_y, m_widthShow, this->height()));
    frameAnimation->setEndValue(QRect(m_xHide, m_y, m_widthHide, this->height()));
    animationGroup->addAnimation(frameAnimation);         // 添加属性动画到动画组
}

//重新计算位置
void SlidingSideWindow::anewRecordPos()
{
    // 设置变形部件尺寸
    m_widthHide = 61;
    m_widthShow = this->width();
    m_widthChange = m_widthShow - m_widthHide;
    m_xShow = this->x();
    m_xHide = this->x() + m_widthChange / 2;
    m_y = this->y();

    animationGroupConfig();
}

模糊知识点

  1. QPropertyAnimation::setDirection(Direction )设置动画的播放方向
  2. Q_PROPERTY将成员变量(或者称为属性)公开为可由其他对象访问和操作的属性
Q_PROPERTY 宏的基本语法如下:
Q_PROPERTY(type name READ getterFunction [WRITE setterFunction] [RESET resetFunction]
               [NOTIFY notifySignal] [REVISION int]
               [DESIGNABLE bool] [SCRIPTABLE bool] [STORED bool]
               [USER bool] [CONSTANT] [FINAL])
其中,常用的属性选项包括:

type:属性的数据类型。
name:属性的名称。
READ getterFunction:返回属性值的函数。
WRITE setterFunction:设置属性值的函数(可选)。
NOTIFY notifySignal:当属性值发生变化时发出的信号(可选)。

源码

Gitee:07SlidingSideWindow滑动侧边栏

相关文章
|
2月前
如何删除PPT中工具栏口袋动画
如何删除PPT中工具栏口袋动画
40 0
|
3月前
|
小程序
【微信小程序-原生开发】实用教程18 - 九宫格、底部悬停按钮、页内悬浮按钮、拨打电话、一键复制
【微信小程序-原生开发】实用教程18 - 九宫格、底部悬停按钮、页内悬浮按钮、拨打电话、一键复制
42 0
|
5月前
|
数据库 iOS开发 MacOS
Lyricsx让歌词悬浮于最顶层
Lyricsx让歌词悬浮于最顶层
73 0
|
5月前
|
前端开发
Flutter笔记:光影动画按钮、滚动图标卡片组等
Flutter笔记:光影动画按钮、滚动图标卡片组等
71 0
|
前端开发
【CSS动画05--闪亮的玻璃图标悬浮效果】
【CSS动画05--闪亮的玻璃图标悬浮效果】
【项目经验】elementui抽屉(从下到上方向)实现向上拉伸
elementui抽屉二次封装(可以向上拉伸)改变抽屉高度
164 0
|
存储 C++ Python
C++复刻:[流光按钮]+[悬浮波纹按钮]
[流光按钮]+[悬浮波纹按钮]
157 0
|
JavaScript Serverless 容器
ue仿携程轮播图效果(滑动轮播,下方高度自适应)
这篇文章主要介绍了vue仿携程轮播图效果(滑动轮播,下方高度自适应),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
【Axure教程】鼠标滚动上下翻页效果
【Axure教程】鼠标滚动上下翻页效果