Jetpack Compose 可讓您以更簡單的方式處理自訂圖形。多數應用程式都必須能夠精準地控制畫面上所繪製的內容。這可能是簡單地將方塊或圓形置於畫面上的正確位置,也可能是精心安排多種不同樣式的圖形元素。透過 Compose 的宣告式方法,所有圖形設定都集中在一處進行,不必劃分為方法呼叫和 Paint
輔助物件。Compose 會有效率地建立及更新所需物件。
Compose 內建的宣告式圖形
Compose 將宣告式方法延伸至圖形處理方式。Compose 的方法提供許多優點:
- Compose 可在圖形元素中盡量減少使用狀態,協助您避免掉入狀態的程式設計誤區。
- 在您進行繪圖時,所有選項都會出現在預期的確切位置,也就是在可組合函式中的正確位置。
- Compose 的圖形 API 能夠有效率地建立及釋放物件。
Canvas
自訂圖形的核心可組合項是 Canvas
。將 Canvas
置入版面配置的方式,與置入其他 Compose UI 元素的方式相同。在 Canvas
中,您可在精準控制樣式和位置的情況下繪製元素。
舉例來說,以下程式碼會建立 Canvas
可組合項,以填滿其父項元素中的所有可用空間:
Canvas(modifier = Modifier.fillMaxSize()) {
}
Canvas
會自動顯示 DrawScope
,這是能自行維護狀態的限定範圍繪圖環境,也能讓您為一組圖形元素設定參數。DrawScope
提供多個實用的欄位,例如 size
,Size
物件可指定 DrawScope
目前的尺寸和尺寸上限。
例如,假設您想繪製從畫布右上角到左下角的對角線,可以新增一個 drawLine
可組合項來執行:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasWidth = size.width val canvasHeight = size.height drawLine( start = Offset(x = canvasWidth, y = 0f), end = Offset(x = 0f, y = canvasHeight), color = Color.Blue ) }
圖 1:使用 drawLine
繪製一條跨畫布的線條。程式碼設定了線條顏色,但使用了預設寬度。
您可以使用其他參數自訂繪圖。例如,根據預設,系統會以髮絲寬度繪製線條,無論繪圖的比例為何,皆顯示為一個像素的寬度。只要設定 strokeWidth
值即可覆寫這個預設值:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasWidth = size.width val canvasHeight = size.height drawLine( start = Offset(x = canvasWidth, y = 0f), end = Offset(x = 0f, y = canvasHeight), color = Color.Blue, strokeWidth = 5F ) }
圖 2:透過覆寫預設寬度來修改圖 1 中的線條。
系統還提供眾多其他簡單的繪圖函式,例如 drawRect
和 drawCircle
。舉例來說,以下程式碼會在畫布中央繪製一個實心圓,其直徑等於畫布短邊尺寸的一半:
Canvas(modifier = Modifier.fillMaxSize()) {
val canvasWidth = size.width
val canvasHeight = size.height
drawCircle(
color = Color.Blue,
center = Offset(x = canvasWidth / 2, y = canvasHeight / 2),
radius = size.minDimension / 4
)
}
圖 3:使用 drawCircle
在畫布中央放置一個圓形。根據預設,drawCircle
會繪製實心圓,因此不需明確指定該項設定。
繪圖函式提供實用的預設參數。例如,根據預設,drawRectangle()
會填滿整個父項範圍,而 drawCircle()
的半徑會等於其父項短邊尺寸的一半。就像 Kotlin 的一貫使用方式,如要讓程式碼更加簡潔清楚,建議您善加利用預設的參數值,只要設定需要變更的參數即可。如要善用這項做法,由於您所繪製的元素會根據父項範圍的設定來決定本身的預設設定,因此只要在 DrawScope
繪圖方法中提供明確的參數即可。
DrawScope
如前所述,每個 Compose Canvas
都會顯示一個 DrawScope
,這是限定範圍的繪圖環境,您可在其中實際發出繪圖指令。
舉例來說,以下程式碼會在畫布左上角繪製一個矩形:
Canvas(modifier = Modifier.fillMaxSize()) {
val canvasQuadrantSize = size / 2F
drawRect(
color = Color.Green,
size = canvasQuadrantSize
)
}
您可以使用 DrawScope.inset()
函式調整目前範圍的預設參數、變更繪圖界線並據此平移繪圖。inset()
等作業會套用至對應 lambda 內的所有繪圖作業:
val canvasQuadrantSize = size / 2F
inset(50F, 30F) {
drawRect(
color = Color.Green,
size = canvasQuadrantSize
)
}
DrawScope
還提供其他簡單的轉換作業,例如 rotate()
。舉例來說,以下程式碼可繪製一個矩形,填滿畫布中央九分之一的空間:
val canvasSize = size
val canvasWidth = size.width
val canvasHeight = size.height
drawRect(
color = Color.Gray,
topLeft = Offset(x = canvasWidth / 3F, y = canvasHeight / 3F),
size = canvasSize / 3F
)
圖 4:使用 drawRect
在畫面中央繪製一個實心矩形。
您可以為矩形的 DrawScope
函式套用旋轉作業,藉此旋轉矩形:
rotate(degrees = 45F) {
drawRect(
color = Color.Gray,
topLeft = Offset(x = canvasWidth / 3F, y = canvasHeight / 3F),
size = canvasSize / 3F
)
}
圖 5:我們利用 rotate()
為目前的繪圖範圍套用旋轉作業,將矩形旋轉 45 度。
如果您想為繪圖套用多項轉換作業,最佳方式並不是建立巢狀的 DrawScope
環境,而是使用 withTransform()
函式建立及套用單一轉換作業,並在其中結合所有需要的變更。與針對個別轉換作業發出巢狀呼叫相較,使用 withTransform()
會更有效率,這是因為所有轉換作業都會透過單一作業一併執行,Compose 就不需逐一計算及儲存個別巢狀轉換作業。
例如,以下程式碼會為矩形透用平移和旋轉作業:
withTransform({
translate(left = canvasWidth / 5F)
rotate(degrees = 45F)
}) {
drawRect(
color = Color.Gray,
topLeft = Offset(x = canvasWidth / 3F, y = canvasHeight / 3F),
size = canvasSize / 3F
)
}
圖 6:我們在此使用 withTransform
同時套用旋轉和平移作業,將矩形旋轉並向左搬移。