一、描述
这个类是动画框架的一部分。它用作属性动画的基类。
该类对 QVariants 执行插值。
如果不想将 QVariant 声明为 Qt 属性,则子类化 QVariantAnimation 可以是一种替代方法。但是请注意,在大多数情况下,最好将 QVariant 声明为属性。
并非所有 QVariant 类型都受支持。以下是当前支持的 QVariant 类型列表:
- int
- uint
- double
- float
- QLine
- QLineF
- QPoint
- QPointF
- QSize
- QSizeF
- QRect
- QRectF
- QColor
如果需要对其他variant类型进行插值,包括自定义类型,则必须自己为这些 variant 类型实现插值。为此,可以为给定类型注册一个内插器函数。该函数接受 3 个参数:起始值、结束值和当前进度。
QVariant myColorInterpolator(const QColor &start, const QColor &end, qreal progress)
{
...
return QColor(...);
}
...
qRegisterAnimationInterpolator<QColor>(myColorInterpolator);
另一种选择是重新实现 interpolated(),它返回被内插值的内插值。
二、属性成员
1、currentValue : const QVariant
此属性保存动画的当前值。开始值和结束值之间的内插值,使用当前时间进行进度。该值本身是从 interpolated() 获得的,它在动画运行时被重复调用。
QVariantAnimation 在当前值改变时调用虚函数 updateCurrentValue() 。这对于需要跟踪更新的子类特别有用。 例如,QPropertyAnimation 使用此函数来为 Qt 属性设置动画。
2、duration : int
此属性描述动画的持续时间(以毫秒为单位)。 默认持续时间为 250 毫秒。
3、easingCurve : QEasingCurve
此属性保存动画的缓和曲线。默认情况下,使用线性缓动曲线插值。
QVariantAnimation 将使用 QEasingCurve::valueForProgress() 将动画的“标准化进度”(currentTime / totalDuration)转换为动画实际使用的有效进度。调用 interpolated() 时的进度就是这种有效的进度。
缓和曲线描述当前值如何随着动画的进展而变化。
4、endValue : QVariant
此属性保存动画的结束值。
5、startValue : QVariant
此属性保存动画的可选起始值。如果省略或将空 QVariant 分配为开始值,则动画将在开始时使用结束的位置。
三、成员函数
1、【信号】void valueChanged(const QVariant &value)
currentValue 发生变化时,会发出此信号。
2、QVariant interpolated(const QVariant &from, const QVariant &to, qreal progress)
这个虚函数返回变量 from 和 to 之间的线性插值。可以在 QVariantAnimation 的子类中重新实现这个函数,以提供自己的插值算法。
3、QVariant keyValueAt(qreal step)
返回给定 step 的关键帧值。step 必须在 0 到 1 的范围内。如果 step 没有 KeyValue,则返回无效的 QVariant。
4、QVariantAnimation::KeyValues keyValues()
返回此动画的关键帧。
5、void setKeyValueAt(qreal step, const QVariant &value)
在给定的 step 用给定的 value 创建一个关键帧。step 必须在 0 到 1 的范围内。
6、void setKeyValues(const QVariantAnimation::KeyValues &keyValues)
用给定的 keyValues 替换当前的关键帧集。关键帧的步长必须在 0 到 1 的范围内。
7、void updateCurrentValue(const QVariant &value)
动画的当前值更改时都会调用此虚函数。value 参数是新的当前值。基类实现什么都不做。
四、相关非成员
1、template <typename T> void qRegisterAnimationInterpolator(QVariant (*)(const T &, const T &, qreal) func)
为模板类型 T 注册自定义插值器函数。必须在构造动画之前注册插值器。要取消注册(并使用默认插值器),请将 func 设置为 nullptr。
五、使用示例:自定义类型设置动画的两种方式
5.1、使用 QPropertyAnimation
定义一个结构体 doubleColor ,包含两种颜色,用来填充窗口的上下部分,给它设置动画,观察窗口颜色的变化。
#include <QWidget>
struct doubleColor
{
doubleColor(QColor frist = Qt::red,QColor second = Qt::blue)
:fristColor(frist),secondColor(second)
{}
QColor fristColor;
QColor secondColor;
bool operator !=(const doubleColor & c)
{
return (this->fristColor != c.fristColor) || (this->secondColor != c.secondColor);
}
};
Q_DECLARE_METATYPE(doubleColor)
class Widget : public QWidget
{
Q_OBJECT
Q_PROPERTY(doubleColor color MEMBER color)
public:
Widget(QWidget *parent = nullptr);
~Widget()override;
protected:
void paintEvent(QPaintEvent* e)override;
private:
doubleColor color{(static_cast<void>(Qt::red),Qt::blue)};
};
这里将变量导出为属性,见Qt属性系统。
#include "widget.h"
#include <QPaintEvent>
#include <QPainter>
#include <QPropertyAnimation>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QPropertyAnimation * animation = new QPropertyAnimation(this, "color");
animation->setDuration(4000);
animation->setStartValue(QVariant::fromValue(doubleColor(QColor("#120165"),QColor("#893265"))));
animation->setEndValue(QVariant::fromValue(doubleColor(QColor("#aa3399"),QColor("#cc9937"))));
animation->start(QAbstractAnimation::DeleteWhenStopped);//设置播放完了之后animation清除
connect(animation,&QPropertyAnimation::valueChanged,[this]
{
update();
});
}
Widget::~Widget()
{
}
void Widget::paintEvent(QPaintEvent* e)
{
auto rect = e->rect();
QPainter painter(this);
painter.fillRect(QRect(rect.topLeft(),
QPoint(rect.topRight().x(),rect.topRight().x() + (rect.height()/2))),color.fristColor);
painter.fillRect(QRect(QPoint(rect.topLeft().x(),rect.topLeft().y() + (rect.height()/2)),rect.bottomRight()),color.secondColor);
QWidget::paintEvent(e);
}
#include "widget.h"
#include <QApplication>
#include <QPropertyAnimation>
QVariant myColorInterpolator(const doubleColor &start, const doubleColor &end, qreal progress)
{
auto fr = start.fristColor.red() + ((end.fristColor.red() - start.fristColor.red()) * progress);
auto fg = start.fristColor.green() + ((end.fristColor.green() - start.fristColor.green()) * progress);
auto fb = start.fristColor.blue() + ((end.fristColor.blue() - start.fristColor.blue()) * progress);
auto sr = start.secondColor.red() + ((end.secondColor.red() - start.secondColor.red()) * progress);
auto sg = start.secondColor.green() + ((end.secondColor.green() - start.secondColor.green()) * progress);
auto sb = start.secondColor.blue() + ((end.secondColor.blue() - start.secondColor.blue()) * progress);
return QVariant::fromValue(doubleColor(QColor(fr,fg,fb),QColor(sr,sg,sb)));
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qRegisterAnimationInterpolator<doubleColor>(myColorInterpolator);
Widget w;
w.show();
return a.exec();
}
效果:
5.2、子类化 QVariantAnimation
#include <QWidget>
#include <QVariantAnimation>
struct doubleColor
{
doubleColor(QColor frist = Qt::red,QColor second = Qt::blue)
:fristColor(frist),secondColor(second)
{}
QColor fristColor;
QColor secondColor;
bool operator !=(const doubleColor & c)
{
return (this->fristColor != c.fristColor) || (this->secondColor != c.secondColor);
}
};
Q_DECLARE_METATYPE(doubleColor)
class doubleColrAnimation : public QVariantAnimation
{
Q_OBJECT
public:
doubleColrAnimation(QObject *parent = nullptr)
:QVariantAnimation(parent)
{
}
protected:
QVariant interpolated(const QVariant &from, const QVariant &to, qreal progress) const override
{
doubleColor start = from.value<doubleColor>();
doubleColor end = to.value<doubleColor>();
auto fr = start.fristColor.red() + ((end.fristColor.red() - start.fristColor.red()) * progress);
auto fg = start.fristColor.green() + ((end.fristColor.green() - start.fristColor.green()) * progress);
auto fb = start.fristColor.blue() + ((end.fristColor.blue() - start.fristColor.blue()) * progress);
auto sr = start.secondColor.red() + ((end.secondColor.red() - start.secondColor.red()) * progress);
auto sg = start.secondColor.green() + ((end.secondColor.green() - start.secondColor.green()) * progress);
auto sb = start.secondColor.blue() + ((end.secondColor.blue() - start.secondColor.blue()) * progress);
return QVariant::fromValue(doubleColor(QColor(fr,fg,fb),QColor(sr,sg,sb)));
}
};
class Widget : public QWidget
{
Q_OBJECT
Q_PROPERTY(doubleColor color MEMBER color)
public:
Widget(QWidget *parent = nullptr);
~Widget()override;
protected:
void paintEvent(QPaintEvent* e)override;
private:
doubleColor color{(static_cast<void>(Qt::red),Qt::blue)};
};
#include "widget.h"
#include <QPaintEvent>
#include <QPainter>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
doubleColrAnimation * animation = new doubleColrAnimation(this);
animation->setDuration(4000);
animation->setStartValue(QVariant::fromValue(doubleColor(QColor("#120165"),QColor("#893265"))));
animation->setEndValue(QVariant::fromValue(doubleColor(QColor("#aa3399"),QColor("#cc9937"))));
animation->start(QAbstractAnimation::DeleteWhenStopped);//设置播放完了之后animation清除
connect(animation,&doubleColrAnimation::valueChanged,[this](const QVariant &value)
{
color = value.value<doubleColor>();
update();
});
}
Widget::~Widget()
{
}
void Widget::paintEvent(QPaintEvent* e)
{
auto rect = e->rect();
QPainter painter(this);
painter.fillRect(QRect(rect.topLeft(),
QPoint(rect.topRight().x(),rect.topRight().x() + (rect.height()/2))),color.fristColor);
painter.fillRect(QRect(QPoint(rect.topLeft().x(),rect.topLeft().y() + (rect.height()/2)),rect.bottomRight()),color.secondColor);
QWidget::paintEvent(e);
}
效果和上面的图片一致。