ViewTransition QML Type
指定视图中的过渡项。更多
Import Statement: | import QtQuick |
附加属性
- destination : point
- index : int
- item : item
- targetIndexes : list
- targetItems : list
详细说明
通过ListView 和GridView ,可以指定在视图中的项目因视图模型的修改而发生变化时应应用的转换。它们都具有以下属性,可将其设置为针对各种操作运行的适当转换:
populate
- 应用于最初为视图创建的项或模型更改时的转换add
- 应用于视图创建后添加到视图中的项的转换remove
- 应用于从视图中删除的项的转换move
- 适用于在视图中移动的项(即模型中移动操作的结果)的过渡displaced
- 应用于通过添加、移动或移除操作移位的任何项的通用转换addDisplaced
,removeDisplaced
和moveDisplaced
- 当项目被添加、移动或移除操作移位时将分别应用的转换(如果指定了这些转换,它们将覆盖通用移位转换)
对于Row,Column,Grid 和Flow 定位器类型,由于其操作对象是子项目集合而非数据模型,因此使用以下属性代替:
populate
- 适用于在创建定位器时已添加到定位器的项的过渡add
- 应用于添加到定位器或重新作为定位器的子项目,或已成为定位器的子项目的过渡visiblemove
- 适用于在定位器中移动的项目的过渡,包括因添加或移除其他项目而移动的项目,或在定位器中重新排列的项目,或因调整定位器中其他项目的大小而重新定位的项目。
视图转换可访问 ViewTransition 附加属性,该属性可提供正在转换的项目以及触发转换的操作的详细信息。由于视图转换只针对每个项目运行一次,因此这些详细信息可用于为每个项目定制每次转换。
ViewTransition 附加属性为应用了过渡的项目提供了以下特定属性:
- ViewTransition.item - 过渡中的项目
- ViewTransition.index - 此项目的索引
- ViewTransition.destination--该项目在相关视图操作中移动到的 (x,y) 点
此外,ViewTransition 还为触发过渡操作的目标项目提供了特定属性:
- ViewTransitiontargetIndexes.- 目标项的索引
- ViewTransitiontargetItems.- 目标项本身
(请注意,对于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 毫秒内逐渐增大。此外,任何因添加新项目而移位的项目都将在 400 毫秒内以动画形式移动到其在视图中的新位置,具体过渡时间由displaced
指定。
如果在索引 0 处连续插入五个项目,效果会是这样:
请注意,上述NumberAnimation 对象不需要指定target
就能使相应的项目动画化。此外,addTransition
中的NumberAnimation 也无需指定to
值,即可将项目移动到视图中的正确位置。这是因为,如果未明确定义target
和to
值,视图会用正确的项目和最终项目位置值隐式地设置这些属性。
最简单的视图转换可能只是在视图操作后将项目动画到其新位置(如上文displaced
转换所做的那样),或者将某些项目属性动画化(如上文add
转换所做的那样)。此外,视图转换还可以利用 ViewTransition 附加属性为不同的项目定制动画行为。以下是一些实现该功能的示例。
使用 ViewTransition 附加属性
如前所述,各种 ViewTransition 属性可提供与被过渡的各个项目以及触发过渡的操作相关的详细信息。在上面的动画中,索引 0 处连续插入了五个项目。当插入第五个也是最后一个项目时,将 "项目 4 "添加到视图中,add
过渡运行一次(针对插入的项目),displaced
过渡运行四次(针对视图中现有的四个项目各运行一次)。
此时,如果我们查看为底部被移除的项目("项目 0")运行的displaced
过渡,为该过渡提供的 ViewTransition 属性值如下:
属性 | 值 | 说明 |
---|---|---|
ViewTransition.item | "项目 0 "委托实例 | 项目 0"Rectangle 对象本身 |
ViewTransition.index | int 的值 4 | 添加操作后 "项目 0 "在模型中的索引 |
ViewTransition.destination | point 值为(0, 120) | 项目 0 "移动到的位置 |
ViewTransition.targetIndexes | int 数组,只包含整数 "0"(零) | 项目 4 "的索引,即添加到视图中的新项目 |
ViewTransition.targetItems | 对象数组,仅包含 "项目 4 "委托实例 | 项目 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
过渡的修改。它添加了一个带有嵌套NumberAnimation 对象的ParallelAnimation ,该对象引用 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 } } } }
这将使新添加的项目沿路径产生动画效果。请注意,每条路径都是相对于每个项目的最终目的地点指定的,因此在不同索引处插入的项目会从不同位置开始其路径:
处理中断的动画
如果在原视图转换过程中需要应用不同的视图转换,则视图转换可能会随时中断。例如,在索引 0 处插入项目 A 并进行 "添加 "转换;然后,在项目 A 的转换完成之前,又在索引 0 处快速插入项目 B。由于项目 B 是在项目 A 之前插入的,它将置换项目 A,导致视图中途中断项目 A 的 "添加 "转换,转而在项目 A 上开始 "置换 "转换。
对于只需将物品移动到最终目的地的简单动画,这种中断不太可能需要额外的考虑。但是,如果过渡改变了其他属性,这种中断可能会产生不必要的副作用。请看本页的第一个示例,为方便起见,下面重复这个示例:
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,从而避免了之前错误的视觉效果:
同样的原理也适用于任何视图转换组合。添加的项目可能在其添加过渡结束前被移动,或移动的项目可能在其移动过渡结束前被移除,等等;因此,经验法则是每个过渡都应处理相同的属性集。
有关脚本动作的限制
视图转换初始化时,会评估任何引用 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
序列都会将项目的颜色动画为 "黄色",然后将其动画到最终位置,然后使用ScriptAction 将项目颜色变回 "浅钢蓝色"。但是,运行时,过渡并没有产生预期的结果:
只有最后移动的项目才恢复为 "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,随后将按照预期以正确的 item 目标运行。
附加属性文档
ViewTransition.index : int |
此附加属性保存正在转换的项目的索引。
请注意,如果项目被移动,该属性将保存项目移动到的索引,而不是移动自的索引。
ViewTransition.item : item |
此附加属性包含正在转换的项目。
警告: 此项目不应在过渡之外保留和引用,因为它可能会随着视图的改变而失效。
ViewTransition.targetIndexes : list |
此附加属性包含视图中作为相关操作目标的项的索引列表。
目标是作为操作对象的项。对于添加操作,这些是被添加的项目;对于移除操作,这些是被移除的项目;对于移动操作,这些是被移动的项目。
例如,如果过渡是由插入操作触发的,该插入操作在索引 1 和 2 处添加了两个项目,则 targetIndexes 列表的值为 [1,2]。
注意: targetIndexes 列表只包含实际在视图中的项的索引,或者相关操作完成后将在视图中的项的索引。
ViewTransition.targetItems : list |
此附加属性包含视图中作为相关操作目标的项目列表。
目标是作为操作对象的项目。对于添加操作,这些是正在添加的项目;对于移除操作,这些是正在移除的项目;对于移动操作,这些是正在移动的项目。
例如,如果过渡是由插入操作触发的,该插入操作在索引 1 和 2 处添加了两个项目,那么 targetItems 列表就会包含这两个项目。
注意: targetItems 列表只包含实际在视图中的项目,或者相关操作完成后将在视图中的项目。
警告: 此列表中的对象不应在转场之外保留和引用,因为这些项目可能会失效。targetItems 仅在初始创建过渡时有效;这也意味着它们不应被过渡中的ScriptAction 对象使用,因为在运行过渡之前不会对其进行评估。
© 2025 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.