MonoKelvin 2024-08-03 10:22 采纳率: 44.4%
浏览 8

Qt如何实现Win11导航列表选中项左侧蓝条的动画效果

如题,winui3中的导航栏每次切换选择项时,左侧蓝条有个拉伸动画。我现在要用Qt实现这样一个动画效果,但是没有想到好的算法

img

我目前的实现如下:


class ItemBarPrivate
{
public:
    int offset = 0;
    bool enableAnimation = true;
    bool backwordMove = false;
    Qt::Orientation orientation = Qt::Vertical;
    QVariantAnimation* posAni = nullptr;
    QVariantAnimation* lenAni = nullptr;
    QParallelAnimationGroup* animationGroup = nullptr;
};

ItemBar::ItemBar(Qt::Orientation ori, QWidget* parent)
    : QWidget(parent)
    , d_ptr(new ItemBarPrivate)
{
    setAttribute(Qt::WA_StyledBackground);
    setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    d_ptr->orientation = ori;
    setProperty("orientation", ori == Qt::Vertical ? "vertical" : "horizontal");

    d_ptr->posAni = new QVariantAnimation(this);
    d_ptr->posAni->setDuration(300);
    d_ptr->posAni->setEasingCurve(QEasingCurve::OutQuart);

    d_ptr->lenAni = new QVariantAnimation(this);
    d_ptr->lenAni->setDuration(300);
    d_ptr->lenAni->setEasingCurve(QEasingCurve::OutQuad);

    connect(d_ptr->posAni, &QVariantAnimation::valueChanged, [=](const QVariant& val) { 
        if (d_ptr->posAni->state() != QAbstractAnimation::Running)
            return;

        const QPoint newPos = val.toPoint();
        move(newPos);
    });

    connect(d_ptr->lenAni, &QVariantAnimation::valueChanged, [=](const QVariant& val) {
        if (d_ptr->lenAni->state() != QAbstractAnimation::Running)
            return;
        
        const QSize newSize = val.toSize();
        resize(newSize);
    });

    d_ptr->animationGroup = new QParallelAnimationGroup(this);
    d_ptr->animationGroup->addAnimation(d_ptr->posAni);
    d_ptr->animationGroup->addAnimation(d_ptr->lenAni);
}

QSize ItemBar::sizeHint() const
{
    return d_ptr->orientation == Qt::Vertical ? QSize(4, 16) : QSize(16, 4);
}

void ItemBar::moveEvent(QMoveEvent* evt)
{
    if (!d_ptr->enableAnimation)
        return QWidget::moveEvent(evt);

    if (d_ptr->animationGroup->state() != QAbstractAnimation::Running)
    {
        QPoint oldPos = evt->oldPos();
        QPoint newPos = evt->pos();
        QSize oldSize = sizeHint();
        QSize newSize = oldSize;
        if (d_ptr->orientation == Qt::Vertical)
        {
            d_ptr->backwordMove = oldPos.y() < newPos.y();

            newSize.rheight() *= 4;
            newPos.rx() += d_ptr->offset;
        }
        else 
        {
            d_ptr->backwordMove = oldPos.x() < newPos.x();

            newSize.rwidth() *= 4;
            newPos.ry() += d_ptr->offset;
        }

        if (d_ptr->backwordMove)
        {
            d_ptr->posAni->setEasingCurve(QEasingCurve::OutCubic);
            d_ptr->lenAni->setEasingCurve(QEasingCurve::OutQuad);
        }
        else
        {
            d_ptr->posAni->setEasingCurve(QEasingCurve::OutQuart);
            d_ptr->lenAni->setEasingCurve(QEasingCurve::OutQuad);
        }

        d_ptr->posAni->setStartValue(oldPos);
        d_ptr->posAni->setEndValue(newPos);
        
        d_ptr->lenAni->setStartValue(oldSize);
        d_ptr->lenAni->setKeyValueAt(0.5, (oldSize + newSize) / 2);
        d_ptr->lenAni->setEndValue(oldSize);

        d_ptr->animationGroup->start();
    }
}
  • 写回答

1条回答 默认 最新

  • 专家-司宇[在线] 2024-08-03 10:22
    关注

    引自免费微信小程序:皆我百晓生

    看起来你已经实现了一个基础的动画框架,你可以在此基础上进行扩展以模仿Windows 11导航列表选中项左侧蓝条的动画效果。具体地,你可能需要在moveEvent中做更多的工作来实现拉伸动画的效果。我会给你提供一个改进的代码片段来演示如何做到这一点。假设你有一个按钮(或者菜单项)来代表可点击的导航列表项,当该项被选中时,左侧的蓝条可以展示这个动画效果。我会为你创建一个动画来改变蓝条的位置和大小。以下是一个改进的代码示例:

    首先,我们创建一个表示选中项的按钮和左侧的蓝条(例如使用QLabel或者自定义的绘制部件)。然后在按钮被点击时启动动画。我们可以使用QPropertyAnimation来分别控制蓝条的位置和大小。以下是代码示例:

    class ItemBarButton : public QPushButton { /* ... */ }; // 假设这是一个代表菜单项的按钮
    class SelectionBar : public QWidget { /* ... 用QLabel或者其他自定义部件实现左侧的蓝条 */ };
    
    class ItemBar : public QWidget {
        Q_OBJECT
    public:
        ItemBar(Qt::Orientation ori, QWidget* parent = nullptr) : QWidget(parent), ori(ori) { /* ... */ }
        // 添加一个槽函数来处理按钮点击事件并启动动画
    public slots:
        void onButtonClicked() {
            startSelectionBarAnimation(); // 启动动画的函数实现见下文
        }
    private:
        Qt::Orientation ori; // 定义方向属性
        SelectionBar* selectionBar; // 左侧的蓝条部件
        ItemBarButton* button; // 代表菜单项的按钮
        QPropertyAnimation* posAnimation; // 控制蓝条位置的动画
        QPropertyAnimation* sizeAnimation; // 控制蓝条大小的动画
        bool isBackward = false; // 是否向后移动的标志位
    
        void startSelectionBarAnimation() {
            // 设置动画的起始值和结束值等参数,例如位置、大小等
            posAnimation->setStartValue(...); // 设置起始位置等参数
            posAnimation->setEndValue(...); // 设置结束位置等参数
            sizeAnimation->setStartValue(...); // 设置起始大小等参数
            sizeAnimation->setEndValue(...); // 设置结束大小等参数,注意根据方向调整大小变化的方式和范围等参数设置。同时考虑动画的持续时间、曲线类型等属性设置。最后启动动画。 } }; // 根据你的需求实现这些函数。这里只是一个框架性的代码示例。具体的实现细节需要你根据实际的界面设计和需求进行调整和优化。例如你可以通过调整动画曲线的类型(如 `QEasingCurve::OutCubic` 或 `QEasingCurve::OutQuart` 等)来改变动画的速度变化方式,以达到更逼真的效果。同时你也可以考虑添加一些过渡效果,如淡入淡出等,来提升用户体验。另外需要注意的是,你需要根据实际情况来调整动画的起始值、结束值等参数的设置,以及根据界面的设计来绘制左侧的蓝条部分等细节问题。如果你能提供更详细的界面设计需求和要求等背景信息,我可以给出更具体的代码实现和解决方案建议。如果你有其他关于 Qt 开发的问题或需要进一步的帮助,请随时向我提问。
    
    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 8月3日

悬赏问题

  • ¥15 python怎么在已有视频文件后添加新帧
  • ¥20 虚幻UE引擎如何让多个同一个蓝图的NPC执行一样的动画,
  • ¥15 fluent里模拟降膜反应的UDF编写
  • ¥15 MYSQL 多表拼接link
  • ¥15 关于某款2.13寸墨水屏的问题
  • ¥15 obsidian的中文层级自动编号
  • ¥15 同一个网口一个电脑连接有网,另一个电脑连接没网
  • ¥15 神经网络模型一直不能上GPU
  • ¥15 pyqt怎么把滑块和输入框相互绑定,求解决!
  • ¥20 wpf datagrid单元闪烁效果失灵