QQ界面模仿1

10 篇文章 0 订阅

大爱Qt!
QQ中点击联系人或群时,下面的面板是有动态效果的。一时兴起,来实现一下。
[TOC]

效果图

这里写图片描述

原理

其实实现的方法很多,这里我采用的是QPropertyAnimation。由于想重用代码,所以将动画效果封装在一个QWidget中。
基本思路:带封装的QWidget其实和QStackedWidget或QStackedLayout非常像,唯一不同的地方是在界面切换的时候需要增加动态效果。所以封装的接口也仿照QStackedWidget好了。

代码

class XWidgetAnimation : public QParallelAnimationGroup
{
    Q_OBJECT

public:
    XWidgetAnimation(QObject* parent = nullptr) 
        :QParallelAnimationGroup(parent)
    {
        m_posAnimation = createPropertyAnimation("pos");
        m_posAnimation->setStartValue(QPoint(0, 0));
        m_posAnimation->setEndValue(QPoint(0, 0));

        m_sizeAnimation = createPropertyAnimation("size");
        m_sizeAnimation->setStartValue(QSize(0, 0));
        m_sizeAnimation->setEndValue(QSize(0, 0));
    }

    void setTargetObject(QWidget* target)
    {
        m_posAnimation->setTargetObject(target);
        m_sizeAnimation->setTargetObject(target);
    }
    QWidget* targetObject()const{ return qobject_cast<QWidget*>( m_posAnimation->targetObject()); }

    void setEndPos(const QPoint& pos){ m_posAnimation->setEndValue(pos); }
    QPoint endPos()const{ return m_posAnimation->endValue().toPoint(); }

    void setEndSize(const QSize& size){ m_sizeAnimation->setEndValue(size); }
    QSize endSize()const{ return m_sizeAnimation->endValue().toSize(); }

    QPoint startPos()const{ return m_posAnimation->startValue().toPoint(); }
    QSize startSize()const{ return m_sizeAnimation->startValue().toSize(); }

    void setDuration(int msecs)
    {
        m_posAnimation->setDuration(msecs);
        m_sizeAnimation->setDuration(msecs);
    }

private:
    QPropertyAnimation* createPropertyAnimation(const QByteArray &propertyName)
    {
        QPropertyAnimation* animation = new QPropertyAnimation(this);
        animation->setPropertyName(propertyName);
        addAnimation(animation);

        return animation;
    }


    void setStartPos(const QPoint& pos){ m_posAnimation->setStartValue(pos); }
    void setStartSize(const QSize& size){ m_sizeAnimation->setStartValue(size); }

private:
    QPropertyAnimation* m_posAnimation;
    QPropertyAnimation* m_sizeAnimation;

    friend class XAnimationWidget;
};

class XAnimationWidget : public QWidget
{
    Q_OBJECT
public:
    XAnimationWidget(QWidget* parent = nullptr)
        :QWidget(parent),m_preWidget(nullptr), m_currentWidget(nullptr)
    {
        m_toTargetAnimation = new XWidgetAnimation(this);

        m_fromTargetAnimation = new XWidgetAnimation(this);
        m_fromTargetAnimation->setDirection(QAbstractAnimation::Backward);

        connect(m_toTargetAnimation, SIGNAL(finished()), this, SLOT(onAnimationFinished()));
    }

    void addWidget(QWidget* widget)
    {
        Q_ASSERT(!m_widgets.contains(widget));

        m_widgets.append(widget);
        widget->setParent(this);
        if (m_currentWidget)
        {
            widget->setVisible(false);
        }
        else
        {
            widget->move(0, 0);
            widget->resize(this->size());
            widget->setVisible(true);
            m_currentWidget = widget;
        }
    }
    void removeWidget(QWidget* widget)
    {
        m_widgets.removeOne(widget);
        if (m_currentWidget == widget)
        {
            m_currentWidget = nullptr;
        }
    }
    void insertWidget(int index, QWidget* widget){ m_widgets.insert(index, widget); }

    int count()const{ return m_widgets.count(); }

    int currentIndex()const{ return indexOf(m_currentWidget); }
    QWidget* currentWidget()const{ return m_currentWidget; }

    int indexOf(QWidget* widget)const{ return m_widgets.indexOf(widget); }
    QWidget* widget(int index)const{ return m_widgets.at(index); }

    XWidgetAnimation* fromTargetAnimation()const{ return m_fromTargetAnimation; }
    XWidgetAnimation* toTargetAnimation()const{ return m_toTargetAnimation; }

    public slots:
    void setCurrentIndex(int index)
    {
        setCurrentWidget(widget(index));
    }
    void setCurrentWidget(QWidget* widget)
    {
        Q_ASSERT(m_widgets.contains(widget));

        if (m_currentWidget == widget)
            return;

        m_preWidget = m_currentWidget;
        m_currentWidget = widget;

        preCurrentWidgetChangedEvent(m_preWidget, m_currentWidget);

        m_toTargetAnimation->stop();
        m_fromTargetAnimation->stop();
        m_toTargetAnimation->setTargetObject(m_preWidget);
        m_fromTargetAnimation->setTargetObject(m_currentWidget);
        if (m_preWidget)
            m_toTargetAnimation->start();
        if (m_currentWidget)
        {
            m_fromTargetAnimation->start();
            m_currentWidget->setVisible(true);
            m_currentWidget->raise();
        }
    }

private slots:
    void onAnimationFinished()
    {
        if (m_preWidget)
        {
            m_preWidget->setVisible(false);
        }
    }

protected:
    virtual void resizeEvent(QResizeEvent *event)
    {
        m_toTargetAnimation->setStartSize(event->size());
        m_fromTargetAnimation->setStartSize(event->size());
        if (m_currentWidget)
        {
            m_currentWidget->resize(event->size());
        }
    }
    virtual void preCurrentWidgetChangedEvent(QWidget* oldWidget, QWidget* newWidget){}

private:
    QList<QWidget*> m_widgets;
    QWidget*        m_preWidget;
    QWidget*        m_currentWidget;

    XWidgetAnimation*   m_toTargetAnimation;
    XWidgetAnimation*   m_fromTargetAnimation;
};


class MainPanelCenterWidget : public XAnimationWidget
{
    Q_OBJECT
public:
    MainPanelCenterWidget(QWidget* parent = nullptr) 
        :XAnimationWidget(parent)
    {
    }

protected:
    virtual void resizeEvent(QResizeEvent *event)
    {
        XAnimationWidget::resizeEvent(event);
        toTargetAnimation()->setEndSize(event->size());
        fromTargetAnimation()->setEndSize(event->size());
    }
    virtual void preCurrentWidgetChangedEvent(QWidget* oldWidget, QWidget* newWidget)
    {
        int oldIndex = indexOf(oldWidget);
        int newIndex = indexOf(newWidget);
        int width = this->width();

        if (oldIndex < newIndex)
        {
            toTargetAnimation()->setEndPos(QPoint(-width, 0));
            fromTargetAnimation()->setEndPos(QPoint(width, 0));
        }
        else
        {
            toTargetAnimation()->setEndPos(QPoint(width, 0));
            fromTargetAnimation()->setEndPos(QPoint(-width, 0));
        }
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值