😊 今天给大家分享一个摆钟风格的加载动画 😊
效果如下:
最近工作忙起来了 , 后续再分享其他有趣的加载动画吧.
一共三个文件 , 可以直接编译运行
//main.cpp
#include "LoadingAnimWidget.h"
#include <QApplication>
#include <QGridLayout>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
w.setWindowTitle("加载动画 第10季");
QGridLayout * mainLayout = new QGridLayout;
auto* anim1 = new ThreeMovingZoomingBalls;
mainLayout->addWidget(anim1,0,0);
auto* anim2 = new FourRotatingFireBall;
mainLayout->addWidget(anim2,0,1);
auto* anim3 = new CookieMonster;
mainLayout->addWidget(anim3,0,2);
auto* anim4 = new StickCircle;
anim4->setStickColor("lime");
anim4->setStickWidth(16);
anim4->setStickLength(32);
mainLayout->addWidget(anim4,1,0);
auto* anim5 = new PendulumClock;
mainLayout->addWidget(anim5,1,1);
auto* anim6 = new AmpereMeter;
mainLayout->addWidget(anim6,1,2);
w.setLayout(mainLayout);
w.show();
anim1->start();
anim2->start();
anim3->start();
anim4->start();
anim5->start();
anim6->start();
return a.exec();
}
//LoadingAnimWidget.h
#ifndef LOADINGANIMWIDGET_H
#define LOADINGANIMWIDGET_H
#include <QPropertyAnimation>
#include <QWidget>
class LoadingAnimBase:public QWidget
{
Q_OBJECT
Q_PROPERTY(qreal angle READ angle WRITE setAngle)
public:
LoadingAnimBase(QWidget* parent=nullptr);
virtual ~LoadingAnimBase();
qreal angle()const;
void setAngle(qreal an);
public slots:
virtual void exec();
virtual void start();
virtual void stop();
protected:
QPropertyAnimation mAnim;
qreal mAngle;
};
class StickCircle:public LoadingAnimBase
{
Q_OBJECT
public:
explicit StickCircle(QWidget* parent = nullptr);
void setStickLength(qreal len);
void setStickWidth(qreal len);
void setStickColor(const QColor& color);
protected:
void paintEvent(QPaintEvent *event);
private:
qreal mStickLen;
qreal mStickWidth;
QColor mStickColor;
};
class ThreeMovingZoomingBalls:public LoadingAnimBase{//三个一边移动一边缩放的小球
public:
ThreeMovingZoomingBalls(QWidget* parent = nullptr);
protected:
void paintEvent(QPaintEvent*);
};
class FourRotatingFireBall:public LoadingAnimBase{//四个旋转的火球,说他是火球是因为快速转动的时候它有残影,看上去像弧线
public:
FourRotatingFireBall(QWidget* parent = nullptr);
protected:
void paintEvent(QPaintEvent*);
};
class CookieMonster:public LoadingAnimBase{//一个不停吃饼干的怪兽
public:
CookieMonster(QWidget* parent = nullptr);
protected:
void paintEvent(QPaintEvent*);
};
class PendulumClock:public LoadingAnimBase{//吊钟钟摆
public:
PendulumClock(QWidget* parent = nullptr);
protected:
void paintEvent(QPaintEvent*);
};
class AmpereMeter :public LoadingAnimBase{//电流表的指针
public:
AmpereMeter(QWidget* parent = nullptr);
protected:
void paintEvent(QPaintEvent*);
};
#endif
//LoadingAnimWidget.cpp
#include "LoadingAnimWidget.h"
#include <QDebug>
#include <QPaintEvent>
#include <QPainter>
#include <QtMath>
#include <QRandomGenerator>
LoadingAnimBase::LoadingAnimBase(QWidget* parent):QWidget(parent){
mAnim.setPropertyName("angle");
mAnim.setTargetObject(this);
mAnim.setDuration(2000);
mAnim.setLoopCount(-1);//run forever
mAnim.setEasingCurve(QEasingCurve::Linear);
setFixedSize(200,200);
mAngle = 0;
}
LoadingAnimBase::~LoadingAnimBase(){}
void LoadingAnimBase::exec(){
if(mAnim.state() == QAbstractAnimation::Stopped){
start();
}
else{
stop();
}
}
void LoadingAnimBase::start(){
mAnim.setStartValue(0);
mAnim.setEndValue(360);
mAnim.start();
}
void LoadingAnimBase::stop(){
mAnim.stop();
}
qreal LoadingAnimBase::angle()const{ return mAngle;}
void LoadingAnimBase::setAngle(qreal an){
mAngle = an;
update();
}
StickCircle::StickCircle(QWidget *parent) : LoadingAnimBase(parent),
mStickLen(-1),mStickWidth(10),mStickColor("black"){}
void StickCircle::setStickLength(qreal len){
if(len > 0 && len != mStickLen){
mStickLen = len;
update();
}
}
void StickCircle::setStickWidth(qreal len){
if(len > 0 && len != mStickWidth){
mStickWidth = len;
update();
}
}
void StickCircle::setStickColor(const QColor& color){
if(color.isValid() && mStickColor != color){
mStickColor = color;
update();
}
}
void StickCircle::paintEvent(QPaintEvent *event){
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing);
int x = width();
int y = height();
qreal ang = mAngle;
painter.setPen(Qt::NoPen);
painter.translate(x/2,y/2);
QColor lightColor = mStickColor;
lightColor.setAlphaF(0.1);
const int stickw = mStickWidth;//小棍子的宽度
qreal stickl = x / 4;//小棍子的长度
if(mStickLen > 0) stickl = mStickLen;
QColor highlight = mStickColor;
const int startIdx = ang / 30;//开头的深色小棍子的索引号
const int arr[14] = {0,1,2,3,4,5,6,7,8,9,10,11,0,1};
QList<int> hightlightList{arr[startIdx],arr[startIdx+1],arr[startIdx+2]};
QList<qreal> alphaList{0.5,0.75,0.99};//三根深色的小棍子的透明度
for(int i = 0;i < 12;++i){
if(hightlightList.contains(i)){
auto hc = highlight;
hc.setAlphaF(alphaList[0]);
painter.setBrush(QBrush(hc));
alphaList.pop_front();
}
else {
painter.setBrush(QBrush(lightColor));
}
painter.drawRoundedRect(QRectF(-stickw/2,0.375*y -stickl/2-1,stickw,stickl),stickw/2,stickw/2);
auto transform = painter.transform();
transform.rotate(30);
painter.setTransform(transform);
}
}
ThreeMovingZoomingBalls::ThreeMovingZoomingBalls(QWidget* parent):LoadingAnimBase(parent){}
void ThreeMovingZoomingBalls::paintEvent(QPaintEvent*){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
painter.setBrush(QBrush("cadetblue"));
qreal x = width();
qreal y = height();
painter.translate(0,y/2);
const qreal delta = 0.08*x;
const qreal minr = 0.02*x;
for(int i = 0;i < 5;++i){
qreal ang = mAngle + 90*i;
qreal posx = ang/360*x;
if(posx > x) posx -= x;
qreal r = minr + delta * qSin(M_PI / x * posx);
painter.drawEllipse(QPointF(posx,0),r,r);
}
}
FourRotatingFireBall::FourRotatingFireBall(QWidget* parent){}
void FourRotatingFireBall::paintEvent(QPaintEvent*){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QPen pen;
pen.setCapStyle(Qt::RoundCap);
pen.setWidth(12);
painter.setPen(pen);
painter.setBrush(Qt::NoBrush);
const qreal x = width();
const qreal y = height();
const qreal r = 0.4*y;
const qreal maxArc = 30;
for(int i = 0;i <4;++i){
painter.resetTransform();
painter.translate(x/2,y/2);
painter.rotate(90*i);
if(i % 2 == 0){
pen.setColor("lightblue");
painter.setPen(pen);
}
else{
pen.setColor("lightpink");
painter.setPen(pen);
}
if(mAngle < 30){ //启动火球,画出弧线
qreal ratio = mAngle / 30;
painter.drawArc(QRectF(-r,-r,2*r,2*r),16*90,16*-ratio*maxArc);
}
else if(mAngle < 330){//转动两圈
qreal ratio = (mAngle - 30) / 300;
painter.rotate((720-maxArc)*ratio);
painter.drawArc(QRectF(-r,-r,2*r,2*r),16*90,16*-maxArc);
}
else{//收起弧线
qreal ratio = (mAngle - 330) / 30;
painter.drawArc(QRectF(-r,-r,2*r,2*r),16*90,16*(1-ratio)*maxArc);
}
}
}
CookieMonster::CookieMonster(QWidget* parent):LoadingAnimBase(parent){}
void CookieMonster::paintEvent(QPaintEvent*){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
const qreal x = width();
const qreal y = height();
const qreal r = 0.2*x;
painter.setPen(Qt::NoPen);
painter.setBrush(QBrush("royalblue"));
painter.translate(4,y/2);
qreal startAngle = 22.5 + 22.5*qSin(M_PI / 90 * mAngle + M_PI/2);
qreal span = 360 - 2*startAngle;
painter.drawPie(QRectF(0,-r,2*r,2*r),startAngle*16,span*16);
painter.setBrush(QBrush("white"));
painter.drawEllipse(QPointF(r*0.8,-r/2),4,4);
//画移动的小饼干
painter.setBrush(QBrush("lightgreen"));
painter.resetTransform();
painter.translate(x,y/2);
qreal ratio = mAngle / 360;
for(int i = 0;i <3;++i){
ratio += 0.333;
if(ratio > 1) ratio -= 1;
painter.drawEllipse(QPointF( -(x-2*r)*ratio,0 ) , 8,8);
}
}
PendulumClock::PendulumClock(QWidget* parent):LoadingAnimBase(parent){}
void PendulumClock::paintEvent(QPaintEvent*){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
const qreal x = width();
const qreal y = height();
painter.translate(x/2,y/8);
QPen pen("silver");
pen.setWidth(4);
painter.setPen(pen);
painter.rotate(30*qSin(M_PI/180*mAngle));
painter.setBrush(QBrush("silver"));
painter.drawLine(0,0,0,0.6*y);
painter.translate(0,0.6*y);
painter.drawEllipse(QPointF(0,0),16,16);
}
AmpereMeter::AmpereMeter(QWidget* parent):LoadingAnimBase(parent){}
void AmpereMeter::paintEvent(QPaintEvent*){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
const qreal x = width();
const qreal y = height();
painter.translate(x/2,y*0.6);
QPen pen("dimgray");
pen.setWidth(4);
painter.setPen(pen);
painter.setBrush(Qt::NoBrush);
const qreal r = x*0.4;
//step1 先画一个表框
painter.drawArc(QRectF(-r,-r,2*r,2*r),0,180*16);
//step2 再画半圈刻度
qreal gap = 180 / 14.0;
painter.rotate(-90);
for(int i = 1;i <= 13;++i){
painter.rotate(gap);
painter.drawLine(0,-r + 6,0,-r + 8);
}
//step3 画指针
painter.resetTransform();
painter.translate(x/2,y*0.6);
painter.rotate(80*qSin(M_PI/180*mAngle));
painter.drawLine(0,0,0,-r*0.7);
}