如题,winui3中的导航栏每次切换选择项时,左侧蓝条有个拉伸动画。我现在要用Qt实现这样一个动画效果,但是没有想到好的算法
我目前的实现如下:
class ItemBarPrivate
{
public:
int offset = 0;
bool enableAnimation = true;
bool backwordMove = false;
Qt::Orientation orientation = Qt::Vertical;
QVariantAnimation* posAni = nullptr;
QVariantAnimation* lenAni = nullptr;
QParallelAnimationGroup* animationGroup = nullptr;
};
ItemBar::ItemBar(Qt::Orientation ori, QWidget* parent)
: QWidget(parent)
, d_ptr(new ItemBarPrivate)
{
setAttribute(Qt::WA_StyledBackground);
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
d_ptr->orientation = ori;
setProperty("orientation", ori == Qt::Vertical ? "vertical" : "horizontal");
d_ptr->posAni = new QVariantAnimation(this);
d_ptr->posAni->setDuration(300);
d_ptr->posAni->setEasingCurve(QEasingCurve::OutQuart);
d_ptr->lenAni = new QVariantAnimation(this);
d_ptr->lenAni->setDuration(300);
d_ptr->lenAni->setEasingCurve(QEasingCurve::OutQuad);
connect(d_ptr->posAni, &QVariantAnimation::valueChanged, [=](const QVariant& val) {
if (d_ptr->posAni->state() != QAbstractAnimation::Running)
return;
const QPoint newPos = val.toPoint();
move(newPos);
});
connect(d_ptr->lenAni, &QVariantAnimation::valueChanged, [=](const QVariant& val) {
if (d_ptr->lenAni->state() != QAbstractAnimation::Running)
return;
const QSize newSize = val.toSize();
resize(newSize);
});
d_ptr->animationGroup = new QParallelAnimationGroup(this);
d_ptr->animationGroup->addAnimation(d_ptr->posAni);
d_ptr->animationGroup->addAnimation(d_ptr->lenAni);
}
QSize ItemBar::sizeHint() const
{
return d_ptr->orientation == Qt::Vertical ? QSize(4, 16) : QSize(16, 4);
}
void ItemBar::moveEvent(QMoveEvent* evt)
{
if (!d_ptr->enableAnimation)
return QWidget::moveEvent(evt);
if (d_ptr->animationGroup->state() != QAbstractAnimation::Running)
{
QPoint oldPos = evt->oldPos();
QPoint newPos = evt->pos();
QSize oldSize = sizeHint();
QSize newSize = oldSize;
if (d_ptr->orientation == Qt::Vertical)
{
d_ptr->backwordMove = oldPos.y() < newPos.y();
newSize.rheight() *= 4;
newPos.rx() += d_ptr->offset;
}
else
{
d_ptr->backwordMove = oldPos.x() < newPos.x();
newSize.rwidth() *= 4;
newPos.ry() += d_ptr->offset;
}
if (d_ptr->backwordMove)
{
d_ptr->posAni->setEasingCurve(QEasingCurve::OutCubic);
d_ptr->lenAni->setEasingCurve(QEasingCurve::OutQuad);
}
else
{
d_ptr->posAni->setEasingCurve(QEasingCurve::OutQuart);
d_ptr->lenAni->setEasingCurve(QEasingCurve::OutQuad);
}
d_ptr->posAni->setStartValue(oldPos);
d_ptr->posAni->setEndValue(newPos);
d_ptr->lenAni->setStartValue(oldSize);
d_ptr->lenAni->setKeyValueAt(0.5, (oldSize + newSize) / 2);
d_ptr->lenAni->setEndValue(oldSize);
d_ptr->animationGroup->start();
}
}