@jsulm said in How to animate a widget like discord 'zoom animation':
@Marcia3x In the link @jeremy_k gave you there is an example:
QPushButton button("Animated Button");
button.show();
QPropertyAnimation animation(&button, "geometry");
animation.setDuration(10000);
animation.setStartValue(QRect(0, 0, 100, 30));
animation.setEndValue(QRect(250, 250, 100, 30));
animation.start();
Just do not change x/y, only change width/height.
After a lot of search and effort, I did something:
// stackedwidget.h
class StackedWidget : public QStackedWidget
{
Q_OBJECT
public:
enum QEasingCurve::Type m_animationtype = QEasingCurve::Type::OutQuart;
int m_speed = 1000;
int m_now;
int m_next;
bool animation_active = false;
QPoint m_pnow;
QParallelAnimationGroup* animgroup;
StackedWidget(QWidget* parent) : QStackedWidget(parent)
{
QWidget* widget = new QWidget();
QGridLayout* widget_layout = new QGridLayout();
widget->setLayout(widget_layout);
QPushButton* button;
for (size_t i = 0; i < 10; i++)
{
button = new QPushButton();
button->setText("Button " + QString::number(i));
button->setStyleSheet(R"(
background-color: #3c3f45;
border-radius: 4px;
color: rgba(255, 255, 255, 0.4);
font-size: 15px;
font-weight: 600;
)");
widget_layout->addWidget(button);
}
button->setText("Change Page");
connect(button, &QPushButton::clicked, [=]
{
animimateToPage(1);
});
QWidget* widget_2 = new QWidget();
QGridLayout* widget_layout_2 = new QGridLayout();
widget_2->setLayout(widget_layout_2);
for (size_t i = 0; i < 10; i++)
{
button = new QPushButton();
button->setText("================ " + QString::number(i));
button->setStyleSheet(R"(
background-color: #3c3f45;
border-radius: 4px;
color: rgba(255, 255, 255, 0.4);
font-size: 15px;
font-weight: 600;
)");
widget_layout_2->addWidget(button);
}
button->setText("return");
connect(button, &QPushButton::clicked, [this]
{
animimateToPage(0);
});
addWidget(widget);
addWidget(widget_2);
}
void animimateToPage(int index)
{
if (animation_active)
return;
animation_active = true;
int now = currentIndex();
int next = indexOf(widget(index));
int offsetx = frameRect().width();
int offsety = frameRect().height();
widget(next)->setGeometry(0, 0, offsetx, offsety);
QPoint pnext = widget(next)->pos();
QPoint pnow = widget(now)->pos();
m_pnow = pnow;
//widget(next)->move(pnext.x() - offsetx, pnext.y() - offsety);
QRect rnext = widget(next)->geometry();
QRect rnow = widget(now)->geometry();
int addw = 300;
int addh = 100;
widget(next)->show();
widget(next)->raise();
QPropertyAnimation* animnow = new QPropertyAnimation(widget(now), "geometry");
animnow->setDuration(m_speed);
animnow->setEasingCurve(m_animationtype);
animnow->setStartValue(QRect(0, 0, rnow.width(), rnow.height()));
animnow->setEndValue(QRect(0, 0, rnow.width() - addw, rnow.height() - addh));
QGraphicsOpacityEffect* animnow_op_eff = new QGraphicsOpacityEffect();
widget(now)->setGraphicsEffect(animnow_op_eff);
QPropertyAnimation* animnow_op = new QPropertyAnimation(animnow_op_eff, "opacity");
animnow_op->setDuration(m_speed);
animnow_op->setStartValue(1);
animnow_op->setEndValue(0);
QPropertyAnimation* animnext = new QPropertyAnimation(widget(next), "geometry");
animnext->setDuration(m_speed);
animnext->setEasingCurve(m_animationtype);
animnext->setStartValue(QRect(0, 0, rnext.width() - addw, rnext.height() - addh));
animnext->setEndValue(QRect(0, 0, rnext.width(), rnext.height()));
QGraphicsOpacityEffect* animnext_op_eff = new QGraphicsOpacityEffect();
animnext_op_eff->setOpacity(0);
widget(next)->setGraphicsEffect(animnext_op_eff);
QPropertyAnimation* animnext_op = new QPropertyAnimation(animnext_op_eff, "opacity");
animnext_op->setDuration(m_speed);
animnext_op->setStartValue(0);
animnext_op->setEndValue(1);
animgroup = new QParallelAnimationGroup;
animgroup->addAnimation(animnow);
animgroup->addAnimation(animnext);
animgroup->addAnimation(animnow_op);
animgroup->addAnimation(animnext_op);
QObject::connect(animgroup, &QParallelAnimationGroup::finished, this, &StackedWidget::animationDoneSlot);
m_next = next;
m_now = now;
animgroup->start(QAbstractAnimation::DeleteWhenStopped);
}
void animationDoneSlot()
{
setCurrentIndex(m_next);
widget(m_now)->hide();
widget(m_now)->move(m_pnow);
widget(m_now)->setGraphicsEffect(nullptr);
widget(m_next)->setGraphicsEffect(nullptr);
animation_active = false;
}
};
#include "stackedwidget.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
ui.centralWidget->setStyleSheet("#centralWidget { background-color: #36393f; }");
QGridLayout* layout = new QGridLayout();
ui.centralWidget->setLayout(layout);
StackedWidget* stacked_widget = new StackedWidget(this);
layout->addWidget(stacked_widget);
return;
}
I have added some random buttons which colors similar to those seen in discord just to help check if the
animation is 'correct'.
Result:
[image: 27446870-a261-4748-879c-3d04afeb34b8.gif]
Looks like there's any kind of flickering in the animation, and I'm struggling with how to calculate the values to use in
start/end of the geometry animation.
The animation I'm referring to:
https://i.imgur.com/fC2cTCY.gif (i reduced the speed of the animation, also, click on the image to enlarge it)
https://imgur.com/a/nUuOGSn (default speed)