Qt自定义动画移动路径

在使用Qt实现动画时,一般使用QPropertyAnimation来实现,一般我们实现控件的移动动画都是走直线,我们如何实现自己想要的移动路径呢,比如走圆弧。下面介绍通过QPropertyAnimation实现自定义动画移动路径,比如走圆曲线、圆弧曲线等

pos动画属性

#include "myanimation.h"

MyAnimation::MyAnimation(QObject *target, const QByteArray &propertyName, QObject *parent):
    QPropertyAnimation (target, propertyName, parent)
{
    setPathType(LinearPath);
}

void MyAnimation::setPathType(MyAnimation::PathType pathType)
{
    if (pathType >= NPathTypes)
        qWarning("Unknown pathType %d", pathType);

    m_pathType = pathType;
    m_path = QPainterPath();
}

void MyAnimation::updateCurrentTime(int currentTime)
{
    if (m_pathType == CirclePath || m_pathType == ArcPath) {
        if (m_path.isEmpty()) {
            QPointF to = endValue().toPointF();
            QPointF from = startValue().toPointF();
            m_path.moveTo(from);
            if(m_pathType == CirclePath) {
                m_path.addEllipse(QRectF(from, to));
            }
            else {
                qreal tempWidth = from.rx() - to.rx();
                qreal tempHeight = from.ry() - to.ry();
                QRectF tempRect = QRectF(to.x() - tempWidth, to.y(), tempWidth*2, tempHeight*2);
                m_path.arcTo(tempRect, 0, 90);
            }
        }
        int dura = duration();
        const qreal progress = ((dura == 0) ? 1 : ((((currentTime - 1) % dura) + 1) / qreal(dura)));

        qreal easedProgress = easingCurve().valueForProgress(progress);
        if (easedProgress > 1.0) {
            easedProgress -= 1.0;
        } else if (easedProgress < 0) {
            easedProgress += 1.0;
        }
        QPointF pt = m_path.pointAtPercent(easedProgress);
        updateCurrentValue(pt);
        emit valueChanged(pt);
    } else {
        QPropertyAnimation::updateCurrentTime(currentTime);
    }
}

调用

m_pMyAnmation = new MyAnimation(ui->pushButton, "pos", this);
m_pMyAnmation->setDuration(1000);
m_pMyAnmation->setStartValue(QPointF(400, 350));
m_pMyAnmation->setEndValue(QPointF(200, 100));
m_pMyAnmation->setPathType(MyAnimation::ArcPath);

直线动画

圆曲线动画

圆弧曲线

通过重载updateCurrentTime,根据时间节点取到自定义路径的位置,更新updateCurrentValue的值;对于自定义路径,实例中采用QPainterPath绘制圆和圆弧,也可使用QPainterPath绘制直线与圆弧组合等,也可实现其他曲线路径,如sin曲线等。

geometry动画属性

上面例子使用的是pos属性,也可以使用geometry,实现位置与大小组合的动画效果

    QRectF startVal = startValue().toRectF();
    QRectF endVal = endValue().toRectF();

    qreal startWidth = startVal.width();
    qreal startHeight = startVal.height();
    qreal endWidth = endVal.width();
    qreal endHeigth = endVal.height();

    if (m_path.isEmpty()) {
        QPointF to = endVal.topLeft();
        QPointF from = startVal.topLeft();
        m_path.moveTo(from);

        qreal tempWidth = from.rx() - to.rx();
        qreal tempHeight = from.ry() - to.ry();
        QRectF tempRect = QRectF(to.x() - tempWidth, to.y(), tempWidth*2, tempHeight);
        m_path.lineTo(QPointF(from.rx(), from.ry() - tempHeight/2.));
        m_path.arcTo(tempRect, 0, 90);
    }
    int dura = duration();
    const qreal progress = ((dura == 0) ? 1 : ((((currentTime - 1) % dura) + 1) / qreal(dura)));

    qreal easedProgress = easingCurve().valueForProgress(progress);
    if (easedProgress > 1.0) {
        easedProgress -= 1.0;
    } else if (easedProgress < 0) {
        easedProgress += 1.0;
    }
    QPointF pt = m_path.pointAtPercent(easedProgress);

    QSizeF size = QSizeF(endWidth + startWidth * (1 - easedProgress), endHeigth + startHeight * (1 - easedProgress));
    QRectF retRect = QRectF(pt, size);
    updateCurrentValue(retRect);
    emit valueChanged(retRect);

调用:

    m_pMyAnmation = new MyAnimation(ui->pushButton, "geometry", this);
    m_pMyAnmation->setDuration(600);
    m_pMyAnmation->setStartValue(QRectF(400, 350, 60, 50));
    m_pMyAnmation->setEndValue(QRectF(200, 100, 0, 0));

效果

pos的值采用圆弧曲线的方式,size使用线性的方式,即根据运行百分比获取size的大小

运行的进度会再根据easingCurve来取值,所以可以使用设置相应的缓动曲线,具体效果看该博客https://blog.csdn.net/a137748099/article/details/107292996

m_pMyAnmation->setEasingCurve(QEasingCurve::InQuint);

例子代码下载https://download.csdn.net/download/a137748099/18485759

参考:Qt官方例子easing

  • 5
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值