本文源於官網文檔,業餘級翻譯,僅供參考
使用錨點進行定位
基本概念
除了傳統的網格,行,列之外,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; ... }
還有一些提供便利性的錨點,例如anchors.fill可以方便地將組件的左,右,頂部,底部錨線設置爲與目標組件的左,右,頂部,底部錨線一樣。ahchors.centerIn是另一種便捷的錨點,它可以將組件的豎直居中,水平居中錨線設置爲與目標組件的豎直居中,水平居中錨線一樣
錨的外邊距和偏移
錨定系統還允許爲組件的錨設置外邊距(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的方式來清空錨的值。