【发布时间】:2017-08-30 09:32:47
【问题描述】:
将组件的width 或height 设置为零与将其visible 属性设置为false 的效果相同吗?
一个示例用例:
我有一个项目,它滑入窗口。滑动是通过将其高度从0 设置为x 以及当我将这个项目从x 关闭到0 时发生的。不想深入探讨为什么我不对项目的位置设置动画。当项目的高度为 0 时,我应该将其 visible 属性设置为 false 还是没有任何区别?
【问题讨论】:
将组件的width 或height 设置为零与将其visible 属性设置为false 的效果相同吗?
一个示例用例:
我有一个项目,它滑入窗口。滑动是通过将其高度从0 设置为x 以及当我将这个项目从x 关闭到0 时发生的。不想深入探讨为什么我不对项目的位置设置动画。当项目的高度为 0 时,我应该将其 visible 属性设置为 false 还是没有任何区别?
【问题讨论】:
不是真的,除非你剪辑。而且最好尽量避免剪裁。
大小为零的Item 的子级仍然可见。
而将可见设置为 false 将隐藏整个对象树。
在您的特定情况下,只要它不会导致您有不想要的可见剩菜,这似乎并不重要。您当然不希望有诸如 visible: height 之类的绑定,因为这会在动画的每一步都不必要地执行。
为了安全起见,您可以在动画上安装处理程序以切换可见性:
// in the animation
onStarted: if (!item.height) item.visible = true // show if start at 0
onStopped: if (!item.height) item.visible = false // hide if end at 0
如果您将可见性直接绑定到高度,这将避免您获得的持续重新评估,但仍将确保在您的对象开始扩展之前和完成收缩后关闭可见性。
【讨论】:
visible 属性的绑定地狱。
visible 绑定到height,但要注意&& 对此绑定的评估,在某些条件下我知道它不会改变。 QML 在这方面似乎很聪明。除了确保隐藏整个对象树之外,您还可以在查询可见性的位置 上增加界面的清晰度。如果其他程序员想知道它,他需要查询visible、opacity、dimensions,可能还需要查询对象树来确定该项目是否确实可见。我会考虑将visible 设置为正确的值,这是一种很好的做法。
finished 并指望动画不会被异常中断。您不能真正保护评估,因为&& 本身需要评估。此外,它并没有比visible: height 更快。
正如dtech 已经指出的,组件根节点的尺寸不会自动代表底层对象树的尺寸。举个例子:
Item {
id: root
Text {
id: txt
text: 'some text produces implicit width'
}
}
在此示例中,将显示txt 的文本,尽管root 的尺寸为width: 0; height: 0。
正如dtech 已经提到的,您可以将clip 设置为true,但这是不可取的,因为它会被传递给渲染器,渲染器会渲染Item 及其树,最后对其应用剪辑 - 分批进行。
如果你有这样的事情:
Item {
Rectangle {
anchors.fill: parent
color: 'red'
}
}
渲染器在渲染时不会做任何额外的事情,因为它可以与其余的在同一批次中处理。然而,作为开发人员,很难判断大小设置为0 时是否可见。因此建议始终正确设置visible。
我们可以简单地设置
visible: width > 0 && height > 0 && opacity > 0
只要我们不对这些属性中的任何一个进行动画处理或频繁更改它们,它就可以正常工作。至少对于动画我们可能有很好的了解,当这些属性中的任何一个可能变为0 并使用此信息来减少评估量时。
QML 的好处在于,逻辑表达式是从左到右计算的,这意味着在我们的上一个示例中:
width === 0 和height 发生变化,不会触发重新评估height === 0 和width 发生更改,则每次更改都会触发重新评估。这意味着,我们需要把最稳定的条件放在第一位。这可能是我们的关于这些值何时可能改变的信息。我建议使用animation.running 属性来防止在动画运行时重新评估绑定。
让我们举一个更完整的例子:点击后,Rectangle 将从 width: 800 缩小到 width: 0 - 这将使其不可见。
或者三个附加属性binding1, binding2, binding3 绑定到表达式,我们可以使用它们来设置visible。当绑定的特定部分被重新评估时,我们会记录下来。
Rectangle {
id: rect
color: 'red'
width: 800
height: 600
NumberAnimation {
id: ani1
target: rect
property: 'width'
from: 800
to: 0
duration: 3000
}
}
MouseArea {
anchors.fill: parent
onClicked: ani1.running = true
}
property bool binding1: {console.log("1", !rect.width); return !rect.width}
property bool binding2: {!ani1.running && (function() { console.log("2", !rect.width); return !rect.width })()}
property bool binding3: {(function() { console.log("3", !rect.width); return !rect.width })() && !ani1.running}
// equivalent, stripped of the logging:
// property bool binding1: !rect.width
// property bool binding2: !ani1.running && !rect.width
// property bool binding3: !rect.width && !ani1.running
正如我们所见,binding1 会在宽度发生变化时不断重新评估。这是不可取的。
我们可以看到,binding2 仅在创建时评估一次,并且每当 ani 停止运行时。
在binding3 中,我们反其道而行之,我们首先评估width,然后评估ani 是否正在运行。这意味着,只要 width 发生变化,我们就会重新评估。
我们也可以使用信号处理程序 ani.onStarted 和 ani.onStopped 并显式设置可见性,但这不是声明性,QML 鼓励您始终努力保持声明性。 p>
【讨论】:
ListView 的代表,而这个ListView 被包裹在Item 中,我想设置这个Item 的visible 属性如果 ListView 中的所有代表都不可见,则为 false,即他们的 visible 属性为 false。我是否只是简单地遍历ListView 的children 属性并检查其中是否有任何visible = true?听起来有点老套。
QSortFilterProxyModel 来过滤该条件并使用count 属性。如果您不需要该条目的delegate,请在ListView 中使用它。这将自动进行卸载。如果您需要委托(例如因为Timer),请使用原始模型。然后使用 Loader 卸载视觉对象。
ListView 的 contentItem 总大小的猜测将被取消. 2. 滚动时,它们都会被创建。因此,通过使用QSortFilterProxyModel 过滤它们,根本 不拥有它们将为您节省大量不必要的项目的创建和破坏。如果代表有重要的(不可见的)部分,你可能已经搞砸了,因为你不能保证它们的存在(当项目不在视野范围内时)。将它们放在单独的Instantiator 中。