这次和大家分享6个非常清爽的加载动画.
😊 效果如下 😊
一共三个文件 , 可以直接编译运行的呢
//main.cpp
#include "LoadingAnimWidget.h"
#include <QApplication>
#include <QGridLayout>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
w.setWindowTitle("加载动画 第9季");
QGridLayout * mainLayout = new QGridLayout;
auto* anim1 = new ThreeRevolvingBalls;
mainLayout->addWidget(anim1,0,0);
auto* anim2 = new InfinityLoop;
mainLayout->addWidget(anim2,0,1);
auto* anim3 = new Fingerprint;
mainLayout->addWidget(anim3,0,2);
auto* anim4 = new Solitary9Swords;
mainLayout->addWidget(anim4,1,0);
auto* anim5 = new LithiumWave;
mainLayout->addWidget(anim5,1,1);
auto* anim6 = new DotInCircle;
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 ThreeRevolvingBalls:public LoadingAnimBase{
public:
ThreeRevolvingBalls(QWidget* parent = nullptr);//三个绕着中心店旋转和缩放的球
protected:
void paintEvent(QPaintEvent*);
};
class InfinityLoop:public LoadingAnimBase{//一个无穷大标志的双环,上面有一个行星在无尽地绕行
public:
InfinityLoop(QWidget* parent = nullptr);
protected:
void paintEvent(QPaintEvent*);
};
class Fingerprint:public LoadingAnimBase{//一个多层的转动的圆环,像变幻的指纹
public:
Fingerprint(QWidget* parent = nullptr);
protected:
void paintEvent(QPaintEvent*);
};
class Solitary9Swords:public LoadingAnimBase{//六根竖线旋转,中间变幻出18根竖线,有点像独孤九剑在空中的残影
public:
Solitary9Swords(QWidget* parent = nullptr);
protected:
void paintEvent(QPaintEvent*);
};
class LithiumWave:public LoadingAnimBase{//中间是相连的三个小球,它们的转动引起周围波浪发散出去,类似锂离子的三个质子振动
public:
LithiumWave(QWidget* parent = nullptr);
protected:
void paintEvent(QPaintEvent*);
};
class DotInCircle:public LoadingAnimBase{//一个圆圈内部有一个小球绕着内侧轨道转动,模仿的小米手机浏览器的加载动画
public:
DotInCircle(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();
}
ThreeRevolvingBalls::ThreeRevolvingBalls(QWidget* parent ):LoadingAnimBase(parent){}
void ThreeRevolvingBalls::paintEvent(QPaintEvent*){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
const qreal x = width();
const qreal y = height();
painter.setPen(Qt::NoPen);
static const QColor colorList[3] = {"cadetblue" , "coral" , "hotpink"};
painter.translate(x/2,y/2);
painter.rotate(mAngle);
for(int i = 0;i < 3;++i){
painter.setBrush(QBrush(colorList[i]));
const auto r = (0.1+0.03*qSin(M_PI/60*mAngle))*y;
painter.drawEllipse(QPointF(0,-y/6),r,r);
painter.rotate(120);
}
}
InfinityLoop::InfinityLoop(QWidget* parent):LoadingAnimBase (parent){}
void InfinityLoop::paintEvent(QPaintEvent*){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
const qreal x = width();
const qreal y = height();
const qreal r = 0.45*x / (1+qSqrt(2));
static const qreal _sqrt2 = 0.70711;// 1/根号2
painter.setBrush(Qt::NoBrush);
painter.translate(x/2,y/2);
QColor railColor("lightgray");
railColor.setAlphaF(0.5);
QPen pen(railColor);
pen.setWidth(6);
painter.setPen(pen);
//先画一个淡色的轨道
QPainterPath pp;
pp.moveTo(0,0);
pp.lineTo(_sqrt2*r,-_sqrt2*r);
pp.arcTo(QRectF(0.45*x-2*r,-r,2*r,2*r),135,-270);
pp.lineTo(-_sqrt2*r,-_sqrt2*r);
pp.arcTo(QRectF(-0.45*x,-r,2*r,2*r),45,270);
pp.lineTo(0,0);
painter.drawPath(pp);
//画一个小火车
pen.setColor("darkgray");
painter.setPen(pen);
static const int totPercent = 30;
const int rotateAngle = 270;
if(mAngle < rotateAngle){
for(int i = 0;i < totPercent;++i){
qreal percent = mAngle / rotateAngle - 0.01*i;
int tmp = percent*100;
percent = tmp/100.0;//精度不要太高,否则起点会有抖动
if(percent < 0 ) break;
painter.drawEllipse( pp.pointAtPercent(percent) , 2,2);
}
}
else{
int left = (360-mAngle)/(360-rotateAngle) * totPercent;
for(int i = 0;i < left;++i){
painter.drawEllipse(pp.pointAtPercent(1 - 0.01*i),2,2);
}
}
}
Fingerprint::Fingerprint(QWidget* parent):LoadingAnimBase (parent){
mAnim.setDuration(8000);
}
void Fingerprint::paintEvent(QPaintEvent*){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(Qt::NoBrush);
QPen pen("darkseagreen");
pen.setWidth(2);
pen.setCapStyle(Qt::RoundCap);
painter.setPen(pen);
const qreal x = width();
const qreal y = height();
painter.translate(x/2,y/2);
static const int loopNum = 12;//12层指纹
static const int gap = 6;//指纹的间距
static QList<qreal> spanList;
if(spanList.size() <= 0){
for(int i = 0;i < 361;++i)
spanList.push_back(120+60*qSin(M_PI*2/360*i));
}
for(int i = 0;i < loopNum;++i){
const int r = gap*(i+1);
const qreal start = mAngle*(i+1);//越往外,速度越快
const int idx = mAngle;
painter.drawArc(QRectF(-r,-r,r*2,r*2),start*16,16*spanList[idx]);
}
}
Solitary9Swords::Solitary9Swords(QWidget* parent):LoadingAnimBase(parent){
mAnim.setDuration(4000);
}
void Solitary9Swords::paintEvent(QPaintEvent*){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
const qreal x = width();
const qreal y = height();
painter.translate(x/2,y/2);
painter.setBrush(Qt::NoBrush);
static const QColor colorList[3] = {"cadetblue" , "lawngreen" , "lightblue"};
QPen pen;
pen.setCapStyle(Qt::RoundCap);
pen.setWidthF(2);
if(mAngle < 150){
const qreal ratio = mAngle / 150;
for(int i = 0;i < 3;++i){
qreal speed = ratio;
if(i == 0) speed = qPow(ratio,0.4);//最快
else if(i == 1) speed = qPow(ratio,0.6);
else if(i == 2) speed = qPow(ratio,0.99);//最慢
pen.setColor(colorList[i]);
painter.setPen(pen);
for(int a = 0;a < 6;a++){
painter.rotate(60*speed);
painter.drawLine(0,-0.3*y/2,0,-0.9*y/2);
}
painter.resetTransform();
painter.translate(x/2,y/2);
}
}
else if(mAngle < 210){
pen.setColor(colorList[2]);
painter.setPen(pen);
for(int a = 0; a< 6;a++){
painter.drawLine(0,-0.3*y/2,0,-0.9*y/2);
painter.rotate(60);
}
}
else{
const qreal ratio = (mAngle - 210) / 150;
pen.setColor(colorList[2]);
painter.setPen(pen);
painter.drawLine(0,-0.3*y/2,0,-0.9*y/2);
for(int i = 0;i < 3;++i){
qreal speed;
if(i == 0) speed = qPow(ratio,0.4);//最快
else if(i == 1) speed = qPow(ratio,0.6);
else if(i == 2) speed = qPow(ratio,0.99);//最慢
pen.setColor(colorList[i]);
painter.setPen(pen);
for(int a = 1;a <= 5;++a){
painter.rotate(60*a+ (360-a*60)*speed);
painter.drawLine(0,-0.3*y/2,0,-0.9*y/2);
painter.resetTransform();
painter.translate(x/2,y/2);
}
}
}
}
LithiumWave::LithiumWave(QWidget* parent):LoadingAnimBase(parent){}
void LithiumWave::paintEvent(QPaintEvent*){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QPen pen("lightblue");
pen.setWidth(2);
painter.setPen(pen);
painter.setBrush(QBrush("lightblue"));
const qreal x = width();
const qreal y = height();
painter.translate(x/2,y/2);
static const qreal e = 6;//等边三角形的半边长
static const qreal r = 4; //质子半径
qreal zoom = 0.5+ 2*qSin(M_PI / 360 * mAngle);
painter.scale(zoom,zoom);
painter.rotate(mAngle);
//画三个质子
for(int i = 0;i < 3;++i){
painter.drawEllipse(QPointF(0,-sqrt(3) *2/3*e ) , r,r);
painter.drawLine(0, -sqrt(3) *2/3*e,e,sqrt(3)*e/3);
painter.rotate(120);
}
//画5层电磁波
painter.resetTransform();
painter.translate(x/2,y/2);
painter.setBrush(Qt::NoBrush);
for(int i = 0;i < 5;++i){
const qreal ratio = (mAngle - i*40)/200;
if(ratio < 0) break; //最后一层都灭了,后面已经没有波了
if(ratio > 1) continue;//最外层的不要画了
qreal wr = x/2*(0.3 + 0.7*ratio);
QColor c = pen.color();
qreal opacity = qSin(M_PI*ratio);
c.setAlphaF(opacity);
pen.setColor(c);
painter.setPen(pen);
painter.drawEllipse(QPointF(0,0),wr,wr);
}
}
DotInCircle::DotInCircle(QWidget* parent):LoadingAnimBase(parent){}
void DotInCircle::paintEvent(QPaintEvent*){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(Qt::NoBrush);
QPen pen("lightgray");
pen.setWidth(4);
painter.setPen(pen);
const qreal x = width();
const qreal y = height();
painter.translate(x/2,y/2);
painter.drawEllipse(QPointF(0,0),x/4,x/4);
painter.setPen(Qt::NoPen);
painter.setBrush(QBrush("darkgray"));
painter.rotate(mAngle);
static const qreal r = 8;
painter.drawEllipse(QPointF(0,-x/4 +r*2),r,r);
}