1. 程式人生 > >element.ui-Qt實現之Tabs動畫滾動

element.ui-Qt實現之Tabs動畫滾動

視覺和互動參考前端element元件,使用Qt實現
element的Tabs效果
打算使用最簡單的方式實現可滑動的Tabs,繼承於QTabWidget,加入些動畫效果繪製下劃線就搞定了,是不是很簡單。
沒有截動態效果,可自己除錯下劃線有滑動效果

但是其中也有些注意點,這裡也是閱讀qtabwidget.cpp和qstylesheetstyle.cpp原始碼解決

.h檔案

#include <QTabWidget>
#include <QVariantAnimation>

class TabBarAnimation;
class QSimpleSliderNavigation : public QTabWidget
{
	Q_OBJECT

public:
	QSimpleSliderNavigation(QWidget *parent = Q_NULLPTR);
	~QSimpleSliderNavigation();
	void setAnimationCurrentValue(int value);
protected:
	void paintEvent(QPaintEvent *);
	bool eventFilter(QObject *o, QEvent *e);
private:
	void startAnimation(int beginX,int endX,int duration); // 先只考慮橫向的
private:
	TabBarAnimation *animation;
	int m_animationX;
};

.cpp部分

#include "QSimpleSliderNavigation.h"
#include <QStyleOptionTabWidgetFrame>
#include <QStylePainter>
#include <QMouseEvent>


struct TabBarAnimation : public QVariantAnimation {
	TabBarAnimation(QSimpleSliderNavigation* t) : tabs(t)
	{
		setEasingCurve(QEasingCurve::InOutQuad);
	}
	void updateCurrentValue(const QVariant &current) Q_DECL_OVERRIDE;
private:
	QSimpleSliderNavigation* tabs;
};

void TabBarAnimation::updateCurrentValue(const QVariant &current)
{
	if (tabs)
	{
		tabs->setAnimationCurrentValue(current.toInt());
	}
}

//這裡的 QTabWidget::pane {border: none;position: relative;top:2px;} 很重要,將pane的位置下移,這樣繪製的下劃線才能顯示
QSimpleSliderNavigation::QSimpleSliderNavigation(QWidget *parent)
	: QTabWidget(parent)
{
	setStyleSheet("QTabWidget {background-color: rgb(238, 243, 250);} \
				  QTabWidget::pane {border: none;position: relative;top:2px;} \
				  QTabWidget::tab-bar {border: none;} \
				  QTabBar::tab {border: none;min-height: 28px;min-width: 85px;} \
				  QTabBar::tab:hover,QTabBar::tab:selected {color: rgb(88, 187, 228);} \
				  QTabBar::tab:!enabled {background-color: rgb(180, 180, 180);}");

	tabBar()->installEventFilter(this);
	animation = nullptr;
	m_animationX = -1;
}

QSimpleSliderNavigation::~QSimpleSliderNavigation()
{
	if (animation)
	{
		delete animation;
		animation = nullptr;
	}
}

bool QSimpleSliderNavigation::eventFilter(QObject *obj, QEvent *event)
{
	if (obj == tabBar() && event->type() == QEvent::MouseButtonPress)
	{
		QMouseEvent *pMouseEvent = (QMouseEvent *)event;
		if (pMouseEvent->button() == Qt::LeftButton)
		{
			const QPoint pos = pMouseEvent->pos();
			int index = tabBar()->tabAt(pos);
			if (index >= 0)
			{
				int curIndex = tabBar()->currentIndex();
				if (index != curIndex)
				{
					startAnimation(tabBar()->tabRect(curIndex).x(), tabBar()->tabRect(index).x(), 250);
				}
			}
		}
	}

	return false;
}

void QSimpleSliderNavigation::startAnimation(int beginX,int endX,int duration)
{
	if (!animation)
		animation = new TabBarAnimation(this);
	animation->setStartValue(beginX);
	animation->setEndValue(endX);
	animation->setDuration(duration);
	animation->start();
}

void QSimpleSliderNavigation::setAnimationCurrentValue(int value)
{
	m_animationX = value;
	update();
}

//繪製背景下劃線和當前Index的下劃線
void QSimpleSliderNavigation::paintEvent(QPaintEvent *event)
{
	Q_UNUSED(event);
	int index = tabBar()->currentIndex();
	QRect rect = tabBar()->tabRect(index);
	QStyleOptionTabWidgetFrame option;
	initStyleOption(&option);
	option.lineWidth = 0;
	QStylePainter p(this);
	option.rect = style()->subElementRect(QStyle::SE_TabWidgetTabPane, &option, this);
	p.drawPrimitive(QStyle::PE_FrameTabWidget, option);
	p.fillRect(QRect(option.rect.x(), rect.y() + rect.height(),option.rect.width(),1),QColor(228,231,237));
	int x = (animation && animation->state() == QAbstractAnimation::Running) ? m_animationX : rect.x();
	p.fillRect(QRect(x, rect.y() + rect.height(), rect.width(), 2), QColor(88, 187, 228));
}