本文源于官网文档,业余级翻译,仅供参考
除了传统的网格,行,列之外,Qt Quick还提供了一种布局组件的方式,这种方式基于“锚”的概念。每个组件都可以被认为拥有一组不可见的“锚线”,一共7条(如下图):左,水平居中,右,顶部,竖直居中,基线,和底部
基线锚线没有在上图画出,它对应着文本所在的假想线。而对于没有文本的组件而言,基线锚线等同于顶部锚线
Qt Quick的锚定系统允许你在不同组件拥有的锚线之间定义关系,例如,你可以编写如下代码:
Rectangle { id: rect1; ... }
Rectangle { id: rect2; anchors.left: rect1.right; ... }
在这种情况下,rect2的左边沿被绑定到了rect1的右边沿,产生的效果如下图所示
你也可以指定多个锚点,例如
Rectangle { id: rect1; ... }
Rectangle { id: rect2; anchors.left: rect1.right; anchors.top: rect1.bottom; ... }
通过指定多个水平方向或者竖直方向上的锚点,你可以控制一个组件的尺寸,如下所示,rect2被锚定在了rect1的左侧和rect3的右侧,如果任何一个蓝色的矩形被移动了,rect2都会根据实际需要进行拉伸或者收缩
Rectangle { id: rect1; x: 0; ... }
Rectangle { id: rect2; anchors.left: rect1.right; anchors.right: rect3.left; ... }
Rectangle { id: rect3; x: 150; ... }
锚定系统还允许为组件的锚设置外边距(margin)与偏移量(offset),外边距(margin)指定了要保留在组件锚线外部的空白空间的总量,偏移量(offset)则允许基于中心锚线进行定位。一个组件可以通过leftMargin, rightMargin, topMagin, bottomMargin来分别指定其锚边距,或者,使用anchors.margin来为组件的全部四个边沿指定相同的外边距值。锚点的偏移则使horizontalCenterOffset, verticalCenterOffset 和 baselineOffset 指定
下方的示例指定了一个左侧的外边距
Rectangle { id: rect1; ... }
Rectangle { id: rect2; anchors.left: rect1.right; anchors.leftMargin: 5; ... }
在这种情况下,一个宽度为5像素的外边距会被保留在rect2的左侧,产生如下的效果
注意: 锚点的外边距仅对锚生效,他们不是用于设置组件外边距的通用手段。如果为一个组件的某个边沿设置了锚的外边距,而这个边沿却没有锚定到任何其他组件上,那么,此时这个外边距不会生效。
Qt Quick提供了AnchorChanges类型用于指定在某种状态中的锚
State {
name: "anchorRight"
AnchorChanges {
target: rect2
anchors.right: parent.right
anchors.left: undefined //remove the left anchor
}
}
AnchorChanges 可以使用 AnchorAnimation 类型进行动画处理
Transition {
AnchorAnimation {} //animates any AnchorChanges in the corresponding state change
}
锚也可以使用javascript进行强制修改,然而,应当谨慎下达这些修改指令,否则,它们会产生预料之外的结果,下方的示例阐述了这个问题:
//bad code //存在问题的代码
Rectangle {
width: 50
anchors.left: parent.left
function reanchorToRight() {
anchors.right = parent.right
anchors.left = undefined
}
}
当上方示例中的函数reanchorToRight被调用后,该函数首先设置了右侧锚线,在这一刻,左侧和右侧的锚都被设置了,并且组件会被拉伸以填充它的父组件。当左侧锚被取消设置后,新的组件宽度会被保留。因此,当在javascript中更新锚时,你应该先取消任何不再使用的锚点,然后仅仅设置必要的锚,如下所示
Rectangle {
width: 50
anchors.left: parent.left
function reanchorToRight() {
anchors.left = undefined
anchors.right = parent.right
}
}
由于属性绑定的求值顺序是未定义的,因此,不推荐通过条件绑定来修改锚,因为这会导致上方案例中描述的顺序问题。在下方的错误示例代码中,矩形将会不断变宽,直到宽度和父组件一样,这是由于左侧和右侧的锚在属性绑定更新时被同时设置。
//bad code
Rectangle {
width: 50; height: 50
anchors.left: state == "right" ? undefined : parent.left;
anchors.right: state == "right" ? parent.right : undefined;
}
这部分代码应当使用AnchorChanges重写,因为AnchorChanges 会自动在内部处理顺序问题
出于性能方面的考虑,你应该只把组件锚定到它的兄弟组件或者直接父组件上。下方的示例中,锚的设置是非法的,还会生成警告
//bad code
Item {
id: group1
Rectangle { id: rect1; ... }
}
Item {
id: group2
Rectangle { id: rect2; anchors.left: rect1.right; ... } // invalid anchor!
}
还有,基于锚的布局不能和绝对定位混合使用。如果一个组件在指定了其自身的x属性的同时还设置了anchors.left或者,在锚定了左边沿与右边沿的情况下额外设置了一个宽度,都会导致不明确的结果,由于无法清晰明确地判断组件是否应当使用锚定位还是绝对定位。这对于在设置组件的y属性及高度的同时设定anchors.top和anchors.bottom是一样的。同样的情况也会在使用像Row, Col和Grid之类的定位工具时发生,因为这些工具会设置组件的x属性与y属性。如果你希望将基于锚定位变更到基于绝对定位,你可以通过设置锚为undefined的方式来清空锚的值。