【Qt】QStackWidget动画(2)

QStackWidget 切换动画的实现方式,通过重写 QWidget 实现

使用重写实现的切换动画使用和展示上更稳定,推荐使用当前这个。

.h 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#ifndef MYSTACKWIDGET_H
#define MYSTACKWIDGET_H

#include <QPropertyAnimation>

class MyStackWidget : public QWidget
{
Q_OBJECT

public:
MyStackWidget(QWidget *parent);
~MyStackWidget();

int addWidget(QWidget *widget); //添加控件
int insertWidget(int index, QWidget *widget); //插入控件
void removeWidget(QWidget *widget); //删除控件

int count() const; //目前控件数

void setWidgetsVisible(); //设置控件可见

void setCurrentWidget(QWidget *widget); //设置当前widget显示
void setCurrentIndex(int index);
int currentIndex() const; //获取当前显示位置

QWidget *currentWidget() const; //获取当前显示的控件
QWidget *widget(int index) const;
int indexOf(QWidget *widget) const; //获取widget所在位置

void setDuration(int duration); //设置动画时长

protected:
void resizeEvent(QResizeEvent *event);

signals:
void widgetRemoved(int);
void currentChanged(int);

private slots:
void onValueChanged(const QVariant &value);

private:
QList<QWidget *> m_widgetLst; //加入的控件链表
QPropertyAnimation *m_moveAnimation; //动画类
int m_curIndex = 0; //当前显示位置
int m_offset = 0; //需要显示的位置与当前显示的位置的偏差
int m_lastIndex = 0; //最后位置
int m_duration = 500; //动画显示时长,单位:ms

void moveAnimationStart(); //启动移动动画
};

#endif // MYSTACKWIDGET_H

.cpp 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include "mystackwidget.h"

#include <QDebug>
#include <QPropertyAnimation>

MyStackWidget::MyStackWidget(QWidget *parent)
: QWidget(parent)
{
m_offset = 0;
m_curIndex = 0;
m_lastIndex = 0;
m_duration = 500;
m_moveAnimation = new QPropertyAnimation(this, "");
m_moveAnimation->setDuration(m_duration);
connect(m_moveAnimation, &QPropertyAnimation::valueChanged, this, &MyStackWidget::onValueChanged);
}

MyStackWidget::~MyStackWidget()
{

}

int MyStackWidget::count() const
{
return m_widgetLst.size();
}

int MyStackWidget::currentIndex() const
{
return m_curIndex;
}

void MyStackWidget::setDuration(int duration)
{
m_duration = duration;
}

int MyStackWidget::addWidget(QWidget * widget)
{
int index = indexOf(widget);
if (index >= 0){
return index;
}
widget->setParent(this);
m_widgetLst.append(widget);
return count() - 1;
}

int MyStackWidget::indexOf(QWidget * widget) const
{
return m_widgetLst.indexOf(widget);
}

int MyStackWidget::insertWidget(int index, QWidget * widget)
{
int curindex = indexOf(widget);
if (curindex >= 0) {
return curindex;
}
widget->setParent(this);
m_widgetLst.insert(index, widget);
return index;
}

QWidget * MyStackWidget::currentWidget() const
{
if (m_curIndex >= 0 && m_curIndex < count()){
return m_widgetLst.at(m_curIndex);
}
return nullptr;
}

QWidget * MyStackWidget::widget(int index) const
{
if (index >= 0 && index < count()) {
return m_widgetLst.at(index);
}
return nullptr;
}

void MyStackWidget::removeWidget(QWidget * widget)
{
int index = indexOf(widget);
if (index >= 0) {
m_widgetLst.removeAll(widget);
emit widgetRemoved(index);
}
}

void MyStackWidget::setCurrentWidget(QWidget * widget)
{
int index = indexOf(widget);
if (index >= 0 && m_curIndex != index) {
setCurrentIndex(index);
}
}

void MyStackWidget::setCurrentIndex(int index)
{
if (index >= 0 && m_curIndex != index) {
m_lastIndex = m_curIndex;
m_curIndex = index;
moveAnimationStart();
emit currentChanged(index);
}
}

void MyStackWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
int size = count();
for (int i = 0; i < size; i++) {
m_widgetLst.at(i)->resize(this->width(), this->height());
}

if (m_moveAnimation->state() == QAbstractAnimation::Running) {
moveAnimationStart();
}
else {
setWidgetsVisible();
}
}

void MyStackWidget::onValueChanged(const QVariant &value)
{
m_offset = value.toInt();
m_widgetLst.at(m_curIndex)->move(m_offset, 0);
if (m_curIndex > m_lastIndex) {
m_widgetLst.at(m_lastIndex)->move(m_offset - this->width(), 0);
}
else {
m_widgetLst.at(m_lastIndex)->move(this->width() + m_offset, 0);
}
}

void MyStackWidget::moveAnimationStart()
{
m_moveAnimation->stop();
setWidgetsVisible();
int startOffset = m_offset;
if (m_curIndex > m_lastIndex) {
if (startOffset == 0) startOffset = this->width();
else startOffset = this->width() - qAbs(startOffset);
}
else {
if (startOffset == 0) startOffset = -this->width();
else startOffset = qAbs(startOffset) - this->width();
}
m_moveAnimation->setDuration(qAbs(startOffset) * m_duration / this->width());
m_moveAnimation->setStartValue(startOffset);
m_moveAnimation->setEndValue(0);
m_moveAnimation->start();
}

void MyStackWidget::setWidgetsVisible()
{
int size = count();
for (int i = 0; i < size; i++) {
if (m_lastIndex == i || m_curIndex == i)
m_widgetLst.at(i)->setVisible(true);
else {
m_widgetLst.at(i)->setVisible(false);
}
}
}

【Qt】QStackWidget动画(2)
https://hodlyounger.github.io/B_Code/Qt/动画/【Qt】QStackWidget动画2/
作者
mingming
发布于
2023年10月27日
许可协议