属性 绑定动画 属性 与多个动画

Property Binding on Animated Property vs Multiple Animations

考虑这个例子:

import QtQuick 2.7
import QtQuick.Controls 2.0

ApplicationWindow {
    id: appWindow
    width: 1024
    height: 800
    visible: true

    Rectangle {
        id: rect1
        property bool active: true
        opacity: active ? 1 : 0
        height: 300 * opacity
        width: 300 * opacity
        Behavior on opacity { NumberAnimation { duration: 1000 } }
        MouseArea { anchors.fill: parent; onClicked: parent.active = false }
        color: 'cornflowerblue'
    }

    Rectangle {
        id: rect2
        property bool active: true
        x: 305
        opacity: active ? 1 : 0
        height: active ? 300 : 0
        width: active ? 300 : 0
        Behavior on opacity { NumberAnimation { duration: 1000 } }
        Behavior on height { NumberAnimation { duration: 1000 } }
        Behavior on width { NumberAnimation { duration: 1000 } }
        MouseArea { anchors.fill: parent; onClicked: parent.active = false }
        color: 'steelblue'
    }
}

我有两个 Rectangle 具有相同的可观察行为:单击时,它们的不透明度和大小都会消失。

在内部,Animation 的数量不同,即同时 运行 - 1 或 3:

截至目前,我主要使用模式形式 rect1,并且仅在绑定变得不必要地复杂的情况下使用 rect2。但是我想知道,如果动画系统有一些魔力,可以优化单个 属性 的动画,而绑定的性能可能会较低。

在哪些用例中使用模式 rect1 是有益的,什么时候使用 rect2 的方法更明智?

EDIT 还有第三个选项,它尽可能通过 OpacityAnimator 移动到渲染线程。现在我不能再绑定不透明度了,因为它会在动画结束时跳到 0。

Rectangle {
        id: rect3
        property bool active: true
        opacity: active ? 1 : 0
        height: active ? 300 : 0
        x: 610
        width: height
        Behavior on opacity { OpacityAnimator { duration: 1000 } }
        Behavior on height { NumberAnimation { duration: 1000 } }
        MouseArea { anchors.fill: parent; onClicked: parent.active = false }
        color: 'dodgerblue'
    }

编辑 2 解决 Ansh Kumar 的答案: 这是 QML Profiler 的节选。你可以看到,在 rect2 的动画期间既没有绑定也没有 JavaScript 运行,不像 heightwidth 是 [=57] =](有效地) 绑定到 rect1 中的 opacitywidth(有效地) 绑定到 heightrect3.

此外,动画源几乎没有 JS 的踪迹。我无法深入研究它,但似乎只有 ScriptAction 得到 QQMLScriptString,其余的只有将输入从 var 转换为正确的成本类型(如果使用具体动画指定类型,例如NumberAnimation)。
此外,据我所知,每个动画都没有一个循环,但是所有动画都具有某种 update() 左右的功能,即(当 running/registered 时)由单个循环调用(AnimationTimer)。但这是我已经不确定的地方。

现在问题仍然存在:动画的实现是否比优化的 JS 环境更有效,尤其是在创建多个对象和填充时。

QML 中有两种类型的绑定:优化绑定和 non-optimized 绑定。保持绑定表达式尽可能简单是个好主意,因为 QML 引擎使用优化的绑定表达式评估器,它可以评估简单的绑定表达式,而无需切换到完整的 JavaScript 执行环境。与更复杂的 (non-optimized) 绑定相比,这些优化绑定的评估效率要高得多。绑定优化的基本要求是编译时必须知道每个访问的符号的类型信息

当他们知道他们正在使用的对象和属性的类型时,绑定是最快的。动画化 属性 将导致任何引用 属性 的绑定成为 re-evaluated。通常,这是需要的。 opacityheightwidthrect2 中 re-evaluated 进入完整的 JavaScript 执行环境,而在 rect1 中; widthheight 通过优化的绑定表达式求值器并进行优化以提供更有效的绑定,因为它们的对象类型在编译时是已知的。查看 binding and also animations 了解更多详情。

编辑

您关于在 C++ 环境中进行评估的说法是正确的。我找到了以下信息。

渲染引擎应达到一致的 60 frames-per-second 刷​​新率。 60 FPS 意味着每帧之间大约有 16 毫秒(正好是 16.6667 毫秒)可以进行处理,其中包括将绘图图元上传到图形硬件所需的处理。 This 显示动画与垂直刷新同步,因此每 16.66 毫秒一次,并且正好是 pr 帧一次。

while (animationIsRunning) {
    processEvents();
    advanceAnimations();
    paintQMLScene();
    swapAndBlockForNextVSync();
}

因此,在 rect1 中,您已设置 duration: 1000 并将 heightopacity (height: 300 * opacity) 绑定,类似地 widthopacity,所以绑定应该调用 60 次左右?如果您看到 statisticsQML profiler 输出,您会发现以下

正如预期的那样,调用次数约为 60(正好是 63)。现在,如果您将持续时间更改为 2000,调用次数将增加一倍。

因为300 * opacity需要计算,所以QML应该调用JavaScript环境60次左右(当duration: 1000

正如预期的那样,它被调用了大约 60 次。

NumberAnimation 是用 JavaScript 还是 C++ 实现的?当然,您关于它在 C++ 中实现的说法是正确的,Here 是其声明的 link。因此,在 rect1 中我们使用了 NumberAnimation 一次,在 rect2 中我们使用了 3 次。因此,总共应创建 4 个 NumberAnimation 实例。

因此,rect1 总共有大约 120 个绑定和 JavaScript 调用,而在 rect2 中没有绑定和 JavaScript 调用,因此 rect2 应该会更快,但问题是,会有什么明显的改进吗?因为,QtCreator 的免费版本不附带 CPU 分析器,所以我无法研究问题的那部分 (CPU Usage Qt)。如果有人有 Qt 的商业版本,请告诉我我的假设。我真的认为 rect2 最适合使用,因为调用次数减少了。