视图过渡 QML 类型

指定视图中过渡下的项目。 更多...

导入语句import QtQuick

附加属性

详细描述

ListViewGridView 中,可以指定在视图的模型被修改导致视图中的项目发生变化时应该应用的过渡。它们都具有以下属性,可以将适当的过渡应用于各种操作

  • populate - 应用于视图创建时最初创建的项目或当模型发生变化时应用的过渡
  • add - 应用于在视图创建后添加到视图中的项目的过渡
  • remove - 应用于从视图移除的项目的过渡
  • move - 应用于在视图中移动的项目(即模型中移动操作的结果)的过渡
  • displaced - 添加、移动或移除操作导致的位移的通用过渡
  • addDisplacedremoveDisplacedmoveDisplaced - 分别针对添加、移动或移除操作引起的位移应用的过渡,如果指定的话,将覆盖通用位移过渡

对于使用子项集合而不是数据模型的 RowColumnGridFlow 定位器类型,以下属性被用于替代

  • populate - 应用于创建定位器时已添加到定位器的项目的过渡
  • add - 应用于添加到定位器或重新父化的项目,或变得 可见 的项目
  • move - 应用于在定位器内部移动的项目,包括由于添加或移除其他项目导致的位移,或者当定位器中的其他项目大小调整导致项目重新定位时

视图转换具有访问一个关联属性ViewTransition,该属性提供了正在转换的项的详细信息以及触发转换的操作。由于视图转换对每个项仅运行一次,因此可以用于为每个单独的项定制每个转换。

ViewTransition关联属性提供了以下针对所应用的转换项的特定属性

  • ViewTransition.item - 正在转换的项
  • ViewTransition.index - 项的索引
  • ViewTransition.destination - 与相关视图操作相关的(x,y)点,该项将移动到该点

此外,ViewTransition提供特定于触发转换操作的项的属性

(注:对于RowColumnGridFlow定位器类型,只有当转换由向定位器添加项触发时,move转换才提供这两个额外细节。)

视图转换可以不引用上述任何属性进行编写。这些属性只提供用于定制视图转换的一些额外详细信息。

以下是关于视图转换及其如何使用ViewTransition关联属性来增强视图转换的介绍。

视图转换:简单示例

以下是一个使用视图转换的基本示例。下面的视图指定了对adddisplaced属性进行转换,当向视图中添加项时将执行这些转换。

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值以将项移动到视图中的正确位置。这是因为如果这些属性未明确定义,视图隐式地将正确的项和最终项位置值设置为targetto值。

在最简单的情况下,视图转换可能只是像上面的displaced转换那样动画地移动项到一个新的位置,或者像上面的add转换那样动画一些项属性。此外,视图转换可以利用ViewTransition关联属性来为不同的项定制动画行为。以下是一些如何实现此功能的示例。

使用ViewTransition关联属性

如上所述,各种ViewTransition属性提供了有关正在转换的个别项以及触发转换的操作的详细信息。在上面的动画中,连续在索引0处插入了五个项。当第五个和最后一个插入操作发生,将"Item 4"添加到视图中时,add转换对插入项运行一次,而对视图中现有的四个项运行四次(每个现有项一次)。

在此点,如果我们检查为底部偏移项("Item 0")执行过的displaced过渡,该过渡提供的ViewTransition属性值如下

属性说明
ViewTransition.item"Item 0"委托实例"Item 0"的矩形对象本身
ViewTransition.indexint值4在添加操作后,"Item 0"在模型中的索引
ViewTransition.destination值(0, 120)"Item 0"将要移动到的位置
ViewTransition.targetIndexesint数组,仅包含整数"0"(零)新添加到视图中的"Item 4"的索引
ViewTransition.targetItems对象数组,仅包含"Item 4"委托实例"Item 4"的矩形对象——新添加到视图中的项

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

所以,尽管每个单独执行的过渡中的ViewTransition.item、ViewTransition.index和ViewTransition.destination值不同,但对于每个由特定添加操作触发的adddisplaced过渡,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属性提供了一个引用,指向应用过渡的项。这可以用来访问项的任何属性,自定义属性值,等等。

以下是上一个示例中displaced过渡的修改版。它添加了一个<ा href="qml-qtquick-parallelanimation.html" translate="no">ParallelAnimation,其中嵌套的<ा href="qml-qtquick-numberanimation.html" translate="no">NumberAnimation对象引用ViewTransition.item,以访问过渡开始时每个项目的xy值。这允许每个项目在过渡到最终位置之前相对于其起始点进行动画。这样就允许每个项目在过渡到视图中的最终位置之前先动画到中间位置。

    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)位置,然后移动到视图中的最终、正确的位置。

由于最终的<ão href="qml-qtquick-numberanimation.html" translate="no">NumberAnimation没有指定to值,视图隐式地将此值设置为项目的最终视图位置,因此最后这个动画将把这个项移到正确的位置。如果过渡需要计算项的最终位置,可以通过ViewTransition.destination访问。

您可以用一个<ão href="qml-qtquick-pathanimation.html" translate="no">PathAnimation来代替多个NumberAnimation来动画一个项沿途径的动画。例如,在上一个示例中的add过渡可以增加以下<ão href="qml-qtquick-pathanimation.html" translate="no">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
                }
            }
        }
    }

这会沿着路径动画新添加的项。注意,每个路径相对于每个项目的最终目标点指定,因此不同索引插入的项目从不同位置开始其路径

中断动画处理

如果一个不同的视图过渡需要在原始过渡进行时应用,视图过渡可能在任何时候被中断。例如,假设Item A插入到索引0并且经历了“add”过渡;然后,在Item A的过渡完成之前,快速连续地将Item B插入到索引0。由于Item B是在Item A之前插入的,它会将Item A移位,导致视图在Item A“add”过渡中途中断并且而不是开始Item 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过渡。由于中断,opacityscale动画没有完成,因此产生了不透明度和缩放值小于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,避免了之前的错误视觉效果。

同样的原则适用于任何视图过渡组合。一个添加的项可能在它的添加过渡完成之前被移动,或者一个移动的项可能在它的移动过渡完成之前被删除,等等;因此,一条经验法则就是每个过渡都应处理相同的一组属性。

关于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序列可能将元素的李某色彩动画变为“黄色”,然后动画到最终位置,然后使用ScriptAction将元素颜色变回“浅钢蓝”。然而,当运行过渡时,它并没有产生预期的结果

只有最后一个移动的元素颜色返回到“浅钢蓝”,其他元素保持黄色。这是因为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" }
        }
    }

当过渡初始化时,PropertyActiontarget将被设置为过渡的相应ViewTransition.item,并将在期望的item目标上正确运行。

附加属性文档

ViewTransition.destination : point [只读]

此附加属性持有过渡项在视图中的最终目标位置。

此属性值是一个具有xy属性的point


ViewTransition.index : int [只读]

此附加属性持有正在过渡的项的索引。

请注意,如果项正在被移动,此属性将持有项正在移动到的索引,而不是从的索引。


ViewTransition.item : item [只读]

此附加属性持有正在过渡的项。

警告: 不应在过渡之外保留和引用此项,因为它可能随着视图的变化而变得无效。


ViewTransition.targetIndexes : list [只读]

此附加属性持有视图中相关操作的目标的索引列表。

目标是该操作的主题。对于添加操作,这些是被添加的项;对于删除操作,这些是被删除的项;对于移动操作,这些是被移动的项。

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

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

另请参阅 QtQuick::ViewTransition::targetItems


ViewTransition.targetItems : list [只读]

该附加属性包含视图中等同于相关操作的元素列表。

目标是该操作的主题。对于添加操作,这些是被添加的项;对于删除操作,这些是被删除的项;对于移动操作,这些是被移动的项。

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

注意:targetItems列表仅包含当前在视图中的元素,或者在相关操作完成后将出现在视图中的元素。

警告:列表中的对象不应被保留并用于过渡之外,因为这些对象可能变得无效。targetItems仅在过渡最初创建时有效;这也意味着不应在过渡中的ScriptAction对象中使用它们,这些对象只有在过渡运行时才会被评估。

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


© 2024 Qt公司。此处包含的文档贡献是各自所有者的版权。此处提供的文档根据Free Software Foundation发布的GNU自由文档许可协议版本1.3项下的条款提供。Qt及其相关标志是芬兰和/或全球其他地区的Qt公司的商标。所有其他商标均为其各自所有者的财产。