本页内容

ViewTransition QML Type (Uncreatable)

指定视图中处于过渡状态的项目。更多...

Import Statement: import QtQuick

注意:此类型不可创建。无法在 QML 中实例化。

关联属性

详细说明

通过 `ListView ` 和 `GridView`,可以指定当视图中的项目因视图模型的修改而发生变化时应应用的过渡效果。它们都具有以下属性,可设置为相应的过渡效果,以便针对各种操作执行:

  • populate - 应用于视图初始创建时生成的项,或模型发生变化时的过渡
  • add - 应用于视图创建后被添加到其中的项的过渡效果
  • remove - 应用于从视图中移除的项的过渡
  • move - 适用于在视图内移动的项目(即因模型中的移动操作而产生的移动)
  • displaced - 适用于因添加、移动或移除操作而被替换的任何项的通用过渡
  • addDisplaced,removeDisplaced 和moveDisplaced - 分别适用于项目因添加、移动或移除操作而发生位移时的过渡(如果指定了这些过渡,则它们将覆盖通用位移过渡)

对于Row 、Column 、Grid 和Flow 这几种定位器类型(它们操作的是子项集合而非数据模型),则使用以下属性:

  • populate - 应用于在定位器创建时已添加到其中的项的过渡
  • add - 应用于被添加到定位器或重新关联至定位器的项目,或已变为visible
  • move - 应用于在定位器内部移动的项的过渡,包括因其他项的添加或移除而导致位置发生偏移的情况、在定位器内部以其他方式重新排列项的情况,以及因定位器中其他项调整大小而导致项重新定位的情况

视图过渡可以使用 ViewTransition 附着属性,该属性提供了正在进行过渡的项以及触发过渡的操作的详细信息。由于视图过渡针对每个项仅执行一次,因此可以利用这些详细信息为每个单独的项自定义过渡效果。

ViewTransition 附加属性提供了与过渡所应用的项目相关的以下属性:

  • ViewTransition.item - 正在进行过渡的项
  • ViewTransition.index — 该项的索引
  • ViewTransition.destination - 该项在相关视图操作中移动到的 (x,y) 坐标点

此外,ViewTransition 还提供了针对触发过渡的操作的目标项的特定属性:

(请注意,对于Row 、Column 、Grid 和Flow 这几种定位器类型,move 过渡仅在因向定位器添加项目而触发过渡时,才会提供这两个额外细节。)

编写视图过渡时无需引用上述任何属性。这些属性仅提供有助于自定义视图过渡的额外细节。

以下是对视图过渡的介绍,以及如何利用 ViewTransition 附加属性来增强视图过渡功能。

视图过渡:一个简单示例

以下是一个关于视图过渡使用的基本示例。下面的视图为add 和displaced 属性指定了过渡效果,这些过渡将在向视图添加项目时执行:

ListView {
    width: 240; height: 320
    model: ListModel {}

    delegate: Rectangle {
        width: 100; height: 30
        border.width: 1
        color: "lightsteelblue"
        Text {
            anchors.centerIn: parent
            text: name
        }
    }

    add: Transition {
        NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 400 }
        NumberAnimation { property: "scale"; from: 0; to: 1.0; duration: 400 }
    }

    displaced: Transition {
        NumberAnimation { properties: "x,y"; duration: 400; easing.type: Easing.OutBounce }
    }

    focus: true
    Keys.onSpacePressed: model.insert(0, { "name": "Item " + model.count })
}

按下空格键向模型添加项目时,新项目将在400毫秒内淡入并逐渐放大,同时被添加到视图中。 此外,任何因新增项目而被挤出的项目,都将根据displaced 过渡效果的设定,在400毫秒内动画移动到视图中的新位置。

如果连续在索引 0 处插入五个项目,效果如下:

请注意,上述NumberAnimation 对象无需指定target 即可对相应项进行动画处理。此外,addTransition 中的NumberAnimation 也无需指定to 值即可将项移动到视图中的正确位置。这是因为,如果这些属性未被显式定义,视图会隐式地根据正确的项和最终项位置值设置target 和to 。

最简单的情况下,视图过渡可能只是在视图操作之后将项目动画化地移动到新位置,就像上文中的displaced 过渡那样;或者像上文中的add 过渡那样,对某些项目属性进行动画处理。此外,视图过渡还可以利用ViewTransition附加属性,为不同的项目自定义动画行为。以下是一些实现此功能的示例。

使用 ViewTransition 附加属性

如前所述,各种 ViewTransition 属性不仅提供了与正在进行过渡的单个项目相关的详细信息,还提供了触发该过渡的操作的详细信息。 在上方的动画中,有五个项目依次插入到索引 0 处。当进行第五次也是最后一次插入操作(将“Item 4”添加到视图中)时,add 过渡会运行一次(针对被插入的项目),而displaced 过渡会运行四次(针对视图中现有的四个项目,每个项目各运行一次)。

此时,如果我们检查针对被顶部元素挤出的“Item 0”运行的displaced 过渡,该过渡所使用的ViewTransition属性值如下:

属性值说明
ViewTransition.item“Item 0”委托实例“项 0”的Rectangle 对象本身
ViewTransition.indexint 值为 4在执行 add 操作后,“Item 0”在模型中的索引
ViewTransition.destinationpoint 值为 (0, 120)“项目 0”将移动到的位置
ViewTransition.targetIndexesint 数组中仅包含整数“0”(零)“项 4”的索引,即新添加到视图中的项
ViewTransition.targetItems对象数组中,“Item 4”的索引仅包含“Item 4”委托实例“Item 4”的Rectangle 对象——新增到视图中的项目

ViewTransition.targetIndexes 和 ViewTransition.targetItems 列表提供了作为相关操作目标的所有委托实例的项及其索引。对于添加操作,这些是添加到视图中的所有项;对于删除操作,这些是从视图中移除的所有项,以此类推。 (请注意,这些列表仅包含在视图内创建的项或其缓存项的引用;不在视图可见区域内或不在项缓存中的目标将无法访问。)

因此,虽然每次执行的过渡操作中,ViewTransition.item、ViewTransition.index和ViewTransition.destination的值各不相同,但对于由特定添加操作触发的每个add 和displaced 过渡,ViewTransition.targetIndexes 和ViewTransition.targetItems 的值是相同的。

基于索引延迟动画

由于每次视图过渡都会针对受其影响的每个项目执行一次,因此可以在过渡中使用 ViewTransition 属性来为每个项目的过渡定义自定义行为。例如,前一个示例中的ListView 可以利用此信息,在被替换项目的移动过程中创建涟漪效果。

可以通过修改displaced 过渡来实现这一点,使其根据每个被移位项的索引(由ViewTransition.index提供)与第一个被移除项的索引(由ViewTransition.targetIndexes 提供)之间的差值,延迟该被移位项的动画:

    displaced: Transition {
        id: dispTrans
        SequentialAnimation {
            PauseAnimation {
                duration: (dispTrans.ViewTransition.index -
                        dispTrans.ViewTransition.targetIndexes[0]) * 100
            }
            NumberAnimation { properties: "x,y"; duration: 400; easing.type: Easing.OutBounce }
        }
    }

每个被移位的项目将其动画额外延迟 100 毫秒,当项目因添加操作而被移位时,便会产生一种微妙的涟漪效果,如下所示:

将项目动画化至中间位置

ViewTransition.item 属性提供了一个对正在应用过渡效果的项的引用。可用于访问该项的任何属性、自定义property 值等。

下面是对前一个示例中displaced 过渡效果的修改。它添加了一个ParallelAnimation ,其中嵌套了NumberAnimation 对象,这些对象通过引用ViewTransition.item来获取每个项在过渡开始时的x 和y 值。这使得每个项在动画移动到视图中的最终位置之前,能够先相对于其过渡起始点动画移动到一个中间位置:

    displaced: Transition {
        id: dispTrans
        SequentialAnimation {
            PauseAnimation {
                duration: (dispTrans.ViewTransition.index -
                        dispTrans.ViewTransition.targetIndexes[0]) * 100
            }
            ParallelAnimation {
                NumberAnimation {
                    property: "x"; to: dispTrans.ViewTransition.item.x + 20
                    easing.type: Easing.OutQuad
                }
                NumberAnimation {
                    property: "y"; to: dispTrans.ViewTransition.item.y + 50
                    easing.type: Easing.OutQuad
                }
            }
            NumberAnimation { properties: "x,y"; duration: 500; easing.type: Easing.OutBounce }
        }
    }

现在,一个位置偏移的项目将首先移动到相对于其起始位置的 (20, 50) 处,然后移动到视图中的最终正确位置:

由于最后的NumberAnimation 未指定to 值,视图会隐式地将该值设置为项目在视图中的最终位置,因此最后一次动画将把该项目移动到正确的位置。如果过渡需要项目的最终位置进行某些计算,可通过ViewTransition.destination访问该位置。

与其使用多个 `NumberAnimations`,不如使用 `PathAnimation ` 来沿曲线路径对项目进行动画处理。例如,前一个示例中的 `add ` 过渡可以像下面这样通过 `PathAnimation ` 进行扩展,以使新添加的项目沿路径进行动画:

    add: Transition {
        id: addTrans
        NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 400 }
        NumberAnimation { property: "scale"; from: 0; to: 1.0; duration: 400 }

        PathAnimation {
            duration: 1000
            path: Path {
                startX: addTrans.ViewTransition.destination.x + 200
                startY: addTrans.ViewTransition.destination.y + 200
                PathCurve { relativeX: -100; relativeY: -50 }
                PathCurve { relativeX: 50; relativeY: -150 }
                PathCurve {
                    x: addTrans.ViewTransition.destination.x
                    y: addTrans.ViewTransition.destination.y
                }
            }
        }
    }

这将使新添加的项目沿路径进行动画效果。请注意,每条路径都是相对于每个项目的最终目标点指定的,因此插入到不同索引位置的项目将从不同的位置开始其路径:

处理中断的动画

如果原始过渡正在进行时需要应用另一个视图过渡,则当前视图过渡可能会在任何时候被中断。例如,假设项目 A 被插入到索引 0 并执行“添加”过渡;随后,在项目 A 的过渡尚未完成之前,项目 B 紧接着被插入到索引 0。 由于项目 B 插入的时间早于项目 A,它将取代项目 A,导致视图在中途中断项目 A 的“add”过渡,转而对项目 A 启动“displaced”过渡。

对于仅需将项目动画化移动至最终目标的简单动画,这种中断通常无需额外考虑。但是,如果过渡会改变其他属性,这种中断可能会导致不希望出现的副作用。请参考本页上的第一个示例,为方便起见,下面将其重复一次:

ListView {
    width: 240; height: 320
    model: ListModel {}

    delegate: Rectangle {
        width: 100; height: 30
        border.width: 1
        color: "lightsteelblue"
        Text {
            anchors.centerIn: parent
            text: name
        }
    }

    add: Transition {
        NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 400 }
        NumberAnimation { property: "scale"; from: 0; to: 1.0; duration: 400 }
    }

    displaced: Transition {
        NumberAnimation { properties: "x,y"; duration: 400; easing.type: Easing.OutBounce }
    }

    focus: true
    Keys.onSpacePressed: model.insert(0, { "name": "Item " + model.count })
}

如果多个项目在未等待前一次过渡完成的情况下快速连续添加,结果如下:

每个新添加的项目都会经历add 过渡,但在过渡完成之前,又添加了另一个项目,从而排挤了之前添加的项目。因此,之前添加的项目上的add 过渡被中断,取而代之的是在该项目上启动了displaced 过渡。 由于过渡被中断,opacity 和scale 动画未能完成,导致元素的不透明度和缩放值均低于1.0。

要解决此问题,displaced 过渡还应确保将项的属性设置为add 过渡中指定的结束值,从而在项发生位移时有效重置这些值。在此情况下,这意味着将项的不透明度和缩放比例设置为 1.0:

    displaced: Transition {
        NumberAnimation { properties: "x,y"; duration: 400; easing.type: Easing.OutBounce }

        // ensure opacity and scale values return to 1.0
        NumberAnimation { property: "opacity"; to: 1.0 }
        NumberAnimation { property: "scale"; to: 1.0 }
    }

现在,当项目的“add ”过渡被中断时,其不透明度和缩放比例会在位移时动画调整为 1.0,从而避免了之前出现的错误视觉效果:

同样的原理也适用于任何视图过渡的组合。一个新增的项目可能在“add”过渡结束前就被移动,或者一个已移动的项目可能在“moved”过渡结束前就被移除,以此类推;因此,经验法则是:每个过渡都应处理同一组属性。

关于 ScriptAction 的限制

在初始化视图过渡时,会评估所有引用 ViewTransition 附加属性的属性绑定,以准备过渡。 由于视图过渡内部构造的特性,ViewTransition 附加属性的属性仅在过渡初始化时对相关项有效,而在过渡实际运行时可能已失效。

因此,视图过渡中的ScriptAction 不应引用ViewTransition附加属性,因为当ScriptAction 实际被调用时,它可能无法引用预期的值。请考虑以下示例:

ListView {
    width: 240; height: 320
    model: ListModel {
        Component.onCompleted: {
            for (var i=0; i<8; i++)
                append({"name": i})
        }
    }

    delegate: Rectangle {
        width: 100; height: 30
        border.width: 1
        color: "lightsteelblue"
        Text {
            anchors.centerIn: parent
            text: name
        }
        objectName: name
    }

    move: Transition {
        id: moveTrans
        SequentialAnimation {
            ColorAnimation { property: "color"; to: "yellow"; duration: 400 }
            NumberAnimation { properties: "x,y"; duration: 800; easing.type: Easing.OutBack }
            ScriptAction { script: moveTrans.ViewTransition.item.color = "lightsteelblue" }
        }
    }

    displaced: Transition {
        NumberAnimation { properties: "x,y"; duration: 400; easing.type: Easing.OutBounce }
    }

    focus: true
    Keys.onSpacePressed: model.move(5, 1, 3)
}

按下空格键时,三个项目将从索引 5 移动到索引 1。 对于每个被移动的项目,moveTransition 序列通常会先将项目的颜色动画化为“yellow”,然后将其动画化至最终位置,最后使用ScriptAction 将项目颜色改回“lightsteelblue”。然而,实际运行时,该过渡并未产生预期结果:

只有最后一个被移动的项目恢复为“lightsteelblue”颜色;其余项目仍保持黄色。 这是因为ScriptAction 直到过渡已初始化之后才会被执行,而此时 ViewTransition.item 的值已经发生变化,指向了另一个项目;脚本原本打算引用的项目,并非在实际调用ScriptAction 时由 ViewTransition.item 持有的那个项目。

在此情况下,为避免此问题,视图可以使用PropertyAction 来设置该属性:

    move: Transition {
        id: moveTrans
        SequentialAnimation {
            ColorAnimation { property: "color"; to: "yellow"; duration: 400 }
            NumberAnimation { properties: "x,y"; duration: 800; easing.type: Easing.OutBack }
            //ScriptAction { script: moveTrans.ViewTransition.item.color = "lightsteelblue" } BAD!

            PropertyAction { property: "color"; value: "lightsteelblue" }
        }
    }

当过渡被初始化时,PropertyAction target 将被设置为该过渡对应的 ViewTransition.item,并会在后续按预期以正确的项目目标运行。

附加属性文档

ViewTransition.destination : point [read-only attached]

此附加属性存储了视图中已过渡项的最终目标位置。

该属性的值是一个point ,具有x 和y 属性。

ViewTransition.index : int [read-only attached]

此附加属性保存正在进行过渡操作的项的索引。

请注意,如果该项正在被移动,则此属性表示该项移动到的索引,而非移动的起始索引。

ViewTransition.item : item [read-only attached]

此附加属性保存了正在进行过渡的项。

警告: 不应在过渡之外保留或引用该 项,因为随着视图的变化,它可能会失效。

ViewTransition.targetIndexes : list [read-only attached]

此附加属性包含视图中作为相关操作目标的项目索引列表。

目标即为该操作所涉及的项。对于添加操作,这些是正在被添加的项;对于删除操作,这些是正在被删除的项;对于移动操作,这些是正在被移动的项。

例如,如果过渡是由一个插入操作触发的,该操作在索引 1 和 2 处添加了两个项目,则此 targetIndexes 列表的值将为 [1,2]。

注意: targetIndexes 列表仅包含实际位于视图中的项的索引,或者在相关操作完成后将位于视图中的项的索引。

另请参阅 QtQuick::ViewTransition::targetItems 。

ViewTransition.targetItems : list [read-only attached]

此附加属性保存了视图中作为相关操作目标的项目列表。

目标即为操作的对象。对于添加操作,这些是即将被添加的项目;对于移除操作,这些是即将被移除的项目;对于移动操作,这些是即将被移动的项目。

例如,如果过渡是由一个插入操作触发的,该操作在索引 1 和 2 处添加了两个项,则此 targetItems 列表将包含这两个项。

注意: targetItems 列表仅包含实际位于视图中的项,或将在相关操作完成后进入视图的项。

警告: 不应在过渡之外保留或引用该列表中的对象 ,因为这些项可能会失效。targetItems 仅在过渡最初创建时有效;这也意味着过渡中的ScriptAction 对象不应使用它们,因为这些对象要等到过渡运行时才会被评估。

另请参阅 QtQuick::ViewTransition::targetIndexes 。

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.