StackView 使用总结
- 一、概述
- 二、在应用中使用StackView
- 三、基本的导航
- 1. push Item
- 2. pop Item
- 3. replace Item
- 四、深度链接
- 五、寻找Item
- 六、转换
- 六、Item的所有权
- 七、大小
一、概述
StackView可以与一组相互链接的信息页面一起使用。例如,电子邮件应用程序具有单独的视图,以列出最新的电子邮件,查看特定的电子邮件和列表/查看附件。当用户打开电子邮件时,电子邮件列表视图被压入栈中,当用户选择返回时,电子邮件列表视图又被弹出。
下面的代码片段展示了一个简单的用例,点击相关的按钮,mainView被推入栈中,然后弹出栈中:
ApplicationWindow {
title: qsTr("Hello World")
width: 640
height: 480
visible: true
StackView {
id: stack
initialItem: mainView
anchors.fill: parent
}
Component {
id: mainView
Row {
spacing: 10
Button {
text: "Push"
onClicked: stack.push(mainView)
}
Button {
text: "Pop"
enabled: stack.depth > 1
onClicked: stack.pop()
}
Text {
text: stack.depth
}
}
}
}
二、在应用中使用StackView
在应用程序中使用StackView非常简单,只需将其作为子窗口添加即可。栈通常锚定在窗口的边缘,除了顶部或底部,它可能锚定在状态栏或其他类似的UI组件上。然后可以通过调用栈的导航方法来使用栈。StackView中显示的第一个元素是赋值给initialItem的元素,如果没有设置initialItem,则是最顶层的元素。
三、基本的导航
StackView支持三种主要的导航操作:push()、pop()和replace()。这些操作与经典的栈操作类似,“push”操作将一个元素添加到栈顶,“pop”操作将栈顶的元素删除,而“replace”操作类似于先弹出后推操作,即用新元素替换最上面的元素。栈中最顶层的元素对应于屏幕上当前可见的元素。从逻辑上讲,“push”在应用UI中是向前或更深入的,“pop”是向后导航,而“replace”则是替换当前内容。
1. push Item
在下面的动画中,使用push()函数将三个标签控件压入栈视图:
栈现在包含以下元素:[A, B, C]。
注意:当栈为空时,push()操作将不会有过渡动画,因为没有任何过渡(通常在应用程序启动时)。
2. pop Item
继续上面的例子,调用pop()方法删除栈中最顶层的元素:
栈现在包含以下元素:[A, B]。
注意:对于深度为1或0的栈,pop()操作什么都不会做。在这种情况下,可以使用clear()方法清空栈。
有时,需要返回栈中的多个步骤。例如,返回到应用程序中的“主”项或某种节项。在这种情况下,可以为pop()指定一个元素项作为参数。这称为“unwind”操作,栈将展开,直到指定的元素为止。如果没有找到元素项,stack展开直到只剩下一个元素项,这个元素项就是当前元素。要显式回退到栈的底部,建议使用pop(null),尽管任何不存在的元素都可以。
在下面的动画中,我们通过调用pop(null)将栈unwind到第一个元素:
栈现在只包含一个元素:[a]。
3. replace Item
在下面的动画中,我们将最上面的元素替换为D:
栈现在包含以下元素:[A, B, D]。
四、深度链接
深度链接意味着将应用程序启动到特定状态。例如,可以启动报纸应用程序,绕过最上面的条目,显示特定的文章。就StackView而言,深度链接意味着能够修改栈的状态,以至于可以将一组项目推到栈的顶部,或将栈完全重置为给定状态。
StackView中用于深度链接的API与用于基本导航的API相同。压入一个数组而不是一个元素,会将数组中的所有元素都添加到栈中。然而,过渡动画只应用于数组中的最后一项。push()的一般语义适用于深度链接,也就是说,它添加压入栈的任何内容。
注意:只加载数组的最后一项。剩下的元素只在需要的时候加载,或者在后续调用pop时加载,或者在使用get()获取元素时加载。
给定栈[A, B, C],结果如下:
- push([D, E, F]) => [A, B, C, D, E, F] - "push"过渡动画
- replace([D, E, F]) => [A, B, D, E, F] - “replace” C和F之间的过渡动画
- clear()后面跟着push([D, E, F]) => [D, E, F]:当栈为空时,没有推送元素的过渡动画。
五、寻找Item
调用find()可以找到应用程序没有引用的项。这个方法需要一个回调函数,对栈中的每一项调用(从栈顶开始),直到找到匹配的项为止。如果回调函数返回true, find()将停止查找并返回匹配的项,否则返回null。
下面的代码在堆栈中搜索名为“order_id”的项并展开到该项。
stackView.pop(stackView.find(function(item) {
return item.name == "order_id";
}));
你也可以使用get(index)获取栈中的一个元素。
previousItem = stackView.get(myItem.StackView.index - 1));
六、转换
对于每个push或pop操作,在进入和退出元素时会应用不同的过渡动画。这些动画定义了进入元素的动画方式,以及退出元素的动画方式。我们可以通过为StackView的pushEnter、pushExit、popEnter、popExit、replaceEnter和replaceExit属性指定不同的过渡来定制动画。
注意:过渡动画会影响彼此的过渡行为。为其中一个定制动画而留下另一个可能会得到意想不到的结果。
下面的代码片段为push和pop操作定义了一个简单的渐隐过渡:
StackView {
id: stackview
anchors.fill: parent
pushEnter: Transition {
PropertyAnimation {
property: "opacity"
from: 0
to:1
duration: 200
}
}
pushExit: Transition {
PropertyAnimation {
property: "opacity"
from: 1
to:0
duration: 200
}
}
popEnter: Transition {
PropertyAnimation {
property: "opacity"
from: 0
to:1
duration: 200
}
}
popExit: Transition {
PropertyAnimation {
property: "opacity"
from: 1
to:0
duration: 200
}
}
}
注意:不支持在添加到StackView的项目上使用锚。通常情况下,push、pop和replace转换会对位置进行动画处理,但这在应用锚点时是不可能实现的。请注意,这只适用于项的根。为它的子元素使用锚点的效果符合预期。
六、Item的所有权
StackView只接受它自己创建的项目的所有权。这意味着任何被压入StackView的item都不会被StackView销毁;只有StackView从组件或url中创建的项目才会被StackView销毁。为了说明这一点,下面示例中的消息只会在StackView被销毁时打印,而不会在项目从堆栈弹出时打印:
Component {
id: itemComponent
Item {
Component.onDestruction: print("Destroying second item")
}
}
StackView {
initialItem: Item {
Component.onDestruction: print("Destroying initial item")
}
Component.onCompleted: push(itemComponent.createObject(window))
}
然而,在下面的例子中,从URL和组件中创建的两个项目都会在它们弹出StackView时被销毁:
Component {
id: itemComponent
Item {
Component.onDestruction: print("Destroying second item")
}
}
StackView {
initialItem: "Item1.qml"
Component.onCompleted: push(itemComponent)
}
七、大小
StackView不会从压入它的元素中继承隐式的大小。这意味着,例如,将它用作对话框的内容将无法正常工作:
Dialog {
StackView {
initialItem: Rectangle {
width: 200
height: 200
color: "salmon"
}
}
}
有几种方法可以确保StackView在这种情况下有一个大小:
- 在StackView上设置implicitWidth和implicitHeight。
- 为矩形设置implicitWidth和implicitHeight。
- 在对话框上设置contentWidth和contentHeight。
- 指定对话框的大小。