Qt仿iOS的Switch开关实现

最近因为在玩iOS手机,突然觉得人家的开关就是很好看,于是乎自己花了点时间写了一下,下面是效果图,代码中没有使用定时器,而是直接用的属性动画,并且支持横向和竖向动态缩放。
请添加图片描述
实现代码如下:
Switch.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QVariant>
#include <QWidget>

enum class AnimationType
{
    NoAnimation, //没有动画
    PropertyAnimation, //属性动画
};

class QPropertyAnimation;
class Switch : public QWidget
{
    Q_OBJECT

public:
    Switch(QWidget *parent = nullptr);
    ~Switch();

protected:
    virtual void paintEvent(QPaintEvent *e) override;
    virtual void resizeEvent(QResizeEvent *e) override;
    virtual void mousePressEvent(QMouseEvent *e) override;

private slots:
    void OnValueChanged(QVariant);

private:
    void CalcSliderPos();
    void PaintLeftArea(QPainter&,int);
    void PaintRightArea(QPainter&,int);
    void PaintSliderArea(QPainter&,int);

private:
    bool m_IsOpen; //当前状态
    int m_SliderPos; //滑块当前位置
    QColor m_CloseBgColor; //关闭后背景颜色
    QColor m_OpenBgColor; //打开后背景颜色
    QColor m_SliderBgColor; //滑块背景颜色
    AnimationType m_AnimationType; //动画类型
    QPropertyAnimation* m_PropertyAnimation;
};
#endif // WIDGET_H

Swtich.cpp

#include "Switch.h"
#include <QPainter>
#include <QMouseEvent>
#include <QPropertyAnimation>

Switch:: Switch(QWidget *parent)
    : QWidget(parent)
    , m_IsOpen(false)
    , m_SliderPos(0)
    , m_CloseBgColor(Qt::gray)
    , m_OpenBgColor(Qt::green)
    , m_SliderBgColor(Qt::white)
    , m_AnimationType(AnimationType::PropertyAnimation)
    , m_PropertyAnimation(Q_NULLPTR)
{
    switch(m_AnimationType)
    {
    case AnimationType::NoAnimation:
        break;
    case AnimationType::PropertyAnimation:
        m_PropertyAnimation = new QPropertyAnimation(this,"");
        connect(m_PropertyAnimation,&QPropertyAnimation::valueChanged,this,&Switch::OnValueChanged);
        break;
    default:
        break;
    }
}

Switch::~ Switch()
{}

void Switch::CalcSliderPos()
{
    int size=qMin(width(),height());
    if(m_IsOpen){
        if(width()<height()){
            m_SliderPos = this->height()-size;
        }
        else{
            m_SliderPos = width()-size;
        }
    }
    else{
        m_SliderPos = 0;
    }
}

void Switch::resizeEvent(QResizeEvent *e)
{
    CalcSliderPos();
    QWidget::resizeEvent(e);
}

void Switch::mousePressEvent(QMouseEvent *e)
{
    if(Qt::LeftButton==e->button()){
        m_IsOpen=!m_IsOpen;
        switch(m_AnimationType)
        {
        case AnimationType::NoAnimation:
            CalcSliderPos();
            update();
            break;
        case AnimationType::PropertyAnimation:
            if(Q_NULLPTR==m_PropertyAnimation){
                CalcSliderPos();
                update();
            }
            else{
                m_PropertyAnimation->stop();
                if(m_IsOpen){
                    m_PropertyAnimation->setStartValue(0);
                    m_PropertyAnimation->setEndValue(qAbs(width()-height()));
                }
                else{
                    m_PropertyAnimation->setStartValue (qAbs(width()-height()));
                    m_PropertyAnimation->setEndValue(0);
                }
                m_PropertyAnimation->setDuration(200);
                m_PropertyAnimation->start();
            }
            break;
        default:
            break;
        }
    }
}

void Switch::OnValueChanged(QVariant value)
{
    m_SliderPos=value.toInt();
    update();
}

void Switch::paintEvent(QPaintEvent *e)
{
    QPainter painter(this);
    //设置反走样
    painter.setRenderHint(QPainter::Antialiasing,  true);
    int size=qMin(width(),height());
    PaintLeftArea(painter,size);
    PaintRightArea(painter,size);
    PaintSliderArea(painter,size);
    QWidget::paintEvent(e);
}

void Switch::PaintLeftArea(QPainter& painter,int size)
{
    painter.save();
    //计算左边外框线
    QPainterPath painterPath;
    painterPath.addEllipse(0,0,size,size);
    if(width()<height()){
        QPainterPath rectPath;
        rectPath.addRect(0,size/2,size,m_SliderPos);
        QPainterPath ellipsePath;
        ellipsePath.addEllipse(0,m_SliderPos,size,size);
        ellipsePath=ellipsePath.united(rectPath);
        painterPath=painterPath.united(ellipsePath);
    }
    else{
        QPainterPath rectPath;
        rectPath.addRect(size/2,0,m_SliderPos,size);
        QPainterPath ellipsePath;
        ellipsePath.addEllipse(m_SliderPos,0,size,size);
        ellipsePath=ellipsePath.united(rectPath);
        painterPath=painterPath.united(ellipsePath);
    }
    //绘制左边外框-并填充背景色
    painter.setPen(Qt::NoPen);
    if(m_OpenBgColor.isValid()){
        painter.setBrush(Qt::green);
    }
    else{
        painter.setBrush(QColor(m_OpenBgColor));
    }
    painter.drawPath(painterPath);
    painter.restore();
}

void Switch::PaintRightArea(QPainter &painter,int size)
{
    painter.save();
    //计算右边外框线
    QPainterPath painterPath;
    if(width()<height()){
        painterPath.addEllipse(0,height()-size,size,size);
        QPainterPath ellipsePath;
        ellipsePath.addEllipse(0,m_SliderPos,size,size);
        QPainterPath rectPath;
        rectPath.addRect(0,m_SliderPos+size/2,size,height()-m_SliderPos-size);
        ellipsePath=ellipsePath.united(rectPath);
        painterPath=painterPath.united(ellipsePath);
    }
    else{
        painterPath.addEllipse(width()-size,0,size,size);
        QPainterPath ellipsePath;
        ellipsePath.addEllipse(m_SliderPos,0,size,size);
        QPainterPath rectPath;
        rectPath.addRect(m_SliderPos+size/2,0,width()-m_SliderPos-size,size);
        ellipsePath=ellipsePath.united(rectPath);
        painterPath=painterPath.united(ellipsePath);
    }
    //绘制左边外框-并填充背景色
    painter.setPen(Qt::NoPen);
    if(m_CloseBgColor.isValid()){
        painter.setBrush(Qt::gray);
    }
    else{
        painter.setBrush(QColor(m_CloseBgColor));
    }
    painter.drawPath(painterPath);
    painter.restore();
}

void Switch::PaintSliderArea(QPainter &painter,int size)
{
    painter.save();
    //绘制滑块-并填充颜色
    painter.setPen(Qt::NoPen);

    if(m_SliderBgColor.isValid()){
        painter.setBrush(Qt::white);
    }
    else{
        painter.setBrush(QColor(m_SliderBgColor));
    }
    if(width()<height()){
        painter.drawEllipse(0,m_SliderPos,size,size);
    }
    else{
        painter.drawEllipse(m_SliderPos,0,size,size);
    }
    painter.restore();
}

这里的私有变量可以通过共有接口设置以供外部调用设置颜色等。

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值