【发布时间】:2018-02-07 08:45:29
【问题描述】:
QML 中的width/height 和implicitWidth/Height 有什么区别?什么时候应该设置隐式尺寸而不是常规尺寸?什么时候应该从组件/项目中询问隐式尺寸而不是常规尺寸?
【问题讨论】:
-
好问题!我也为此苦苦挣扎了好久!
-
太棒了!很多人在开始使用 QML 时都会遇到这个问题。
QML 中的width/height 和implicitWidth/Height 有什么区别?什么时候应该设置隐式尺寸而不是常规尺寸?什么时候应该从组件/项目中询问隐式尺寸而不是常规尺寸?
【问题讨论】:
通常,implicitHeight/Width 的使用仅在可重用组件中才有意义。
它给出了项目的自然大小的提示,而不强制执行此大小。
我们以Image 为例。图像的自然大小会将图像文件中的一个像素映射到屏幕上的一个像素。但是它允许我们拉伸它,所以大小不是强制的并且可以被覆盖。
假设现在,我们想要一个包含未知尺寸图片的画廊,我们不想扩大,只在必要时缩小它们。所以我们需要存储图像的自然大小。也就是说,隐式高度发挥作用。
Image {
width: Math.max(150, implicitWidth)
height: Math.max(150, implicitHeight)
}
在自定义组件中,您可以选择如何定义尺寸。
一种选择是,让所有维度都与组件root-node 相关,可能是这样的:
Item {
id: root
Rectangle {
width: root.width * 0.2
height: root.height * 0.2
color: 'red'
}
Rectangle {
x: 0.2 * root.width
y: 0.2 * root.height
width: root.width * 0.8
height: root.height * 0.8
color: 'green'
}
}
在这种情况下,对象没有自然大小。对于您为组件设置的每种尺寸,一切都完美无缺。
另一方面,您可能有一个具有自然大小的对象 - 发生这种情况,例如如果你有绝对值
Item {
id: root
property alias model: repeater.model
Repeater {
id: repeater
delegate: Rectangle {
width: 100
height: 100
x: 102 * index
y: 102 * index
}
}
}
在此示例中,您应该向用户提供有关自然尺寸的信息,其中内容不会突出项目。用户可能仍然决定设置较小的尺寸并处理突出,例如通过剪裁,但他需要有关自然尺寸的信息来做出决定。
在许多情况下,childrenRect.height/width 是 implcitHeight/Width 的一个很好的衡量标准,但也有一些例子,这不是一个好主意。 - 例如当item的内容有x: -500时。
一个真实的例子是Flickable,它专门设计用于包含比其自身大小更大的对象。让Flickable 的大小等于内容是不自然的。
在自定义组件中使用scale 时也要小心,因为childrenRect 不会知道缩放。
Item {
id: root
implicitWidth: child.width * child.scale
implicitHeight: child.height * child.scale
Rectangle {
id: child
width: 100
height: 100
scale: 3
color: 'red'
}
}
对于您的评论:我只是不明白为什么设置隐式宽度/高度而不是设置组件根尺寸的宽度/高度更好。
implicitWidht/Height不是必需品 - QtQuick 可以没有它们。它们是为了方便而存在的,应该是约定的。
经验法则
当你想设置一个可复用组件的根节点的维度时,设置
implicitWidth/Height。
在某些情况下,如果节点作为属性公开,则为非根节点设置它。
仅在有理由的情况下才这样做(许多官方组件都没有)。
使用组件时,设置width/height。
【讨论】:
Layout 类型的任何更新?阅读此文档,似乎在布局中使用 implicitX 而不是 x 也是有意义的:doc.qt.io/qt-5/…
我没有确切的答案,但我可以告诉你我发现了什么。一、from the documentation:
implicitWidth : 真实
如果没有宽度或高度,则定义项目的自然宽度或高度 已指定。
大多数项目的默认隐式大小是 0x0,但是有些项目 具有不能被覆盖的固有隐式大小,因为 例如,
Image和Text。
宽度
定义项目的位置和大小。
width 和 height 反映了场景中项目的实际大小。隐式大小是项目本身的某种固有属性。1
我按如下方式使用它们:当我创建一个可以调整大小的新项目时,我在对象2内部设置了一个隐式大小。在使用对象时,我经常从外部显式设置实际大小。
可以通过设置高度和宽度来覆盖对象的隐式大小。
Item {
implicitWidth: text.implicitWidth
implicitHeight: text.implicitHeight
// the rectangle will expand to the real size of the item
Rectangle { anchors.fill: parent; color: "yellow" }
Text { id: text; text: "Lorem ipsum dolor..." }
}
Item {
width: 400
height: 300
TextWithBackground {
// half of the scene, but never smaller than its implicitWidth
width: Math.max(parent.width / 2, implicitWidth)
// the height of the element is equal to implicitHeight
// because height is not explicitly set
}
}
1) 对于某些元素,例如 Text,隐式高度取决于(非隐式)宽度。
2)隐式大小通常取决于其子项的隐式大小。
【讨论】:
Text,implicitWidth 是没有换行时文本将占据的宽度。 contentWidth 是Item 的实际宽度,如果有环绕(如果没有环绕,它等于implicitWidth)。
implicitWidth/Height而不是设置组件根维度的width/height更好。如果我没有在我创建给定组件的位置指定一个,那么设置常规宽度/高度的工作方式与回退相同。
根据内容计算项目的大小时,应该使用隐式大小。虽然在父项上设置 width 或 height 可能会影响其子项的大小,但当您设置隐式大小时,它绝不应该是这种情况。
经验法则
隐式大小只能“冒泡”,即儿童永远不应该 查找其父项的隐式大小以计算自己的 隐式大小,父母都不应该尝试强制其隐式大小 孩子们。
如果您尝试在类似于布局的组件上设置width,它最初会根据其子项的width(而不是implicitWidth)计算其宽度,并且该子项受父母,你最终会得到一个绑定循环。
这就是该属性存在的原因 - 在根据其内容计算项目大小时打破循环依赖关系。
【讨论】:
RowLayout 应该如何表现,如果你不设置它的大小。如果您不设置RowLayout 的大小,则既不使用其附加属性RowLayout 将使用隐式大小的孩子来计算自己的大小。