很多應用程式都必須能精準地控制畫面上所繪製的內容,像是將方塊或圓形放到畫面上的正確位置,或是詳細布置各式多樣的圖形元素。
使用修飾符和 DrawScope
的基本繪圖
在 Compose 中繪製自訂內容時,基本方法是使用修飾元,例如 Modifier.drawWithContent
、Modifier.drawBehind
和 Modifier.drawWithCache
。
舉例來說,想在可組合項後方繪製內容的話,可以使用 drawBehind
修飾符來執行繪圖指令:
Spacer( modifier = Modifier .fillMaxSize() .drawBehind { // this = DrawScope } )
如果您只需要一個可繪製的可組合項,就可以使用 Canvas
可組合項。Canvas
可組合項是 Modifier.drawBehind
的便利包裝函式。將 Canvas
置入版面配置的方式,與置入其他 Compose UI 元素的方式相同。在 Canvas
中繪製元素時,您可以精準控制元素的樣式和位置。
所有繪圖修飾符都會提供 DrawScope
,這是一種限定作用範圍並能維持自身狀態的繪製環境,可用來設定一組圖形元素的參數。DrawScope
提供了多個實用欄位,比如 size
。Size
物件的作用是指定 DrawScope
的目前尺寸。
如要繪製內容,您可以使用 DrawScope
上的眾多繪圖函式。例如,以下程式碼的作用是在畫面左上角繪製矩形:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F drawRect( color = Color.Magenta, size = canvasQuadrantSize ) }
如要進一步瞭解各種繪圖修飾符,請參閱「圖形修飾符」說明文件。
座標系統
想在畫面上繪製內容,就必須知道內容的偏移植 (x
和 y
) 和大小。很多 DrawScope
上的繪製方法採用的是預設參數值提供的位置和大小。預設參數通常會將項目放在畫布的 [0, 0]
點上,並提供會填滿整個繪圖區域的預設 size
,就如上例中左上角的矩形。如果想調整項目的大小和位置,就必須瞭解 Compose 的座標系統。
座標系統的起點 ([0,0]
) 是繪圖區域左上角的像素,x
值增加為向右移,y
值增加為向下移。
舉例來說,如果想繪製一條從畫布右上角到左下角的對角線,可以使用 DrawScope.drawLine()
函式,並用相應的 x 和 y 位置來指定起點和終點的偏移值:
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 ) }
基本轉換
DrawScope
能處理改變繪圖指令執行位置或方式的轉換作業。
縮放
您可以運用 DrawScope.scale()
來依係數增加繪圖作業的大小。scale()
等作業會作用於相應 lambda 中所有的繪圖作業。例如,以下程式碼的作用是將 scaleX
放大 10 倍,將 scaleY
放大 15 倍:
Canvas(modifier = Modifier.fillMaxSize()) { scale(scaleX = 10f, scaleY = 15f) { drawCircle(Color.Blue, radius = 20.dp.toPx()) } }
平移
您可以使用 DrawScope.translate()
將繪圖作業向上、下、左或右移動。例如,以下程式碼的作用是將繪圖右移 100 px,上移 300 px:
Canvas(modifier = Modifier.fillMaxSize()) { translate(left = 100f, top = -300f) { drawCircle(Color.Blue, radius = 200.dp.toPx()) } }
旋轉
您可以運用 DrawScope.rotate()
讓繪圖作業圍繞樞紐點旋轉。例如,以下程式碼的作用是將矩形旋轉 45 度:
Canvas(modifier = Modifier.fillMaxSize()) { rotate(degrees = 45F) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }
插邊
您可以運用 DrawScope.inset()
調整目前 DrawScope
的預設參數,變更繪圖界線並依此平移繪圖:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F inset(horizontal = 50f, vertical = 30f) { drawRect(color = Color.Green, size = canvasQuadrantSize) } }
以下程式碼有效率地在繪圖指令中加上了邊框間距:
多重轉換
如要對繪圖套用多重轉換,請使用 DrawScope.withTransform()
函式。這個函式會建立並執行一個結合所有預定變更項目的轉換作業。使用 withTransform()
會比逐一針對轉換作業進行呼叫更有效率,因為所有轉換都會經由同一項作業執行,Compose 不必分開計算並儲存個別轉換結果。
例如,以下程式碼的作用是對矩形套用平移和旋轉作業:
Canvas(modifier = Modifier.fillMaxSize()) { withTransform({ translate(left = size.width / 5F) rotate(degrees = 45F) }) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }
常見的繪圖作業
繪製文字
在 Compose 中繪製文字時,您通常可以使用 Text
可組合項。不過,如果您使用的是 DrawScope
,或想利用自訂方式來手動繪製文字,可以使用 DrawScope.drawText()
方法。
如要繪製文字,請使用 rememberTextMeasurer
建立 TextMeasurer
,並使用測量器呼叫 drawText
:
val textMeasurer = rememberTextMeasurer() Canvas(modifier = Modifier.fillMaxSize()) { drawText(textMeasurer, "Hello") }
測量文字
繪製文字的做法和其他繪圖指令稍有不同。一般來說,您會在繪圖指令中指定所繪形狀/圖片的大小 (寬度和高度)。繪製文字時,則需要用一些參數來控制轉譯文字的大小,例如字型大小、字型、連字和字母間距。
在 Compose 中,您可以使用 TextMeasurer
量測由上述條件決定的文字大小。如想繪製文字後面的背景,可以從測量到的資訊來掌握文字所占區域的大小:
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixedWidth((size.width * 2f / 3f).toInt()), style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
這個程式碼片段會使文字背景變成粉紅色:
如果調整限制、字型大小或任何會影響測量大小的屬性,系統就會回報新的大小。您可以針對 width
和 height
設定固定大小,文字將符合設定的 TextOverflow
。例如,以下程式碼的作用是以可組合項區域為準,在 ⅓ 高度和 ⅓ 寬度的範圍內轉譯文字,並將 TextOverflow
設為 TextOverflow.Ellipsis
:
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixed( width = (size.width / 3f).toInt(), height = (size.height / 3f).toInt() ), overflow = TextOverflow.Ellipsis, style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
以下是依限制條件繪製,並以刪節號結尾的文字片段:
繪製圖片
如要使用 DrawScope
繪製 ImageBitmap
,請使用 ImageBitmap.imageResource()
載入圖片並呼叫 drawImage
:
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog) Canvas(modifier = Modifier.fillMaxSize(), onDraw = { drawImage(dogImage) })
繪製基本形狀
DrawScope
有很多用來繪製形狀的函式。如要繪製形狀,請使用一個預先定義的繪圖函式,例如 drawCircle
:
val purpleColor = Color(0xFFBA68C8) Canvas( modifier = Modifier .fillMaxSize() .padding(16.dp), onDraw = { drawCircle(purpleColor) } )
API |
輸出 |
繪製路徑
路徑是一連串數學指令,執行後就會建立繪圖。DrawScope
可以使用 DrawScope.drawPath()
方法繪製路徑。
舉例來說,假設您想繪製一個三角形,可以使用 lineTo()
、moveTo()
之類函式以根據繪製區域的大小產生路徑,然後用這個新建立的路徑呼叫 drawPath()
來產生一個三角形。
Spacer( modifier = Modifier .drawWithCache { val path = Path() path.moveTo(0f, 0f) path.lineTo(size.width / 2f, size.height / 2f) path.lineTo(size.width, 0f) path.close() onDrawBehind { drawPath(path, Color.Magenta, style = Stroke(width = 10f)) } } .fillMaxSize() )
存取 Canvas
物件
使用 DrawScope
時,您無法直接存取 Canvas
物件,但可以運用 DrawScope.drawIntoCanvas()
來取得 Canvas
物件本身的存取權,藉此呼叫其中的函式。
舉例來說,如果想在畫布上繪製自訂 Drawable
,可以存取畫布並呼叫 Drawable#draw()
,將其傳遞到 Canvas
物件中:
val drawable = ShapeDrawable(OvalShape()) Spacer( modifier = Modifier .drawWithContent { drawIntoCanvas { canvas -> drawable.setBounds(0, 0, size.width.toInt(), size.height.toInt()) drawable.draw(canvas.nativeCanvas) } } .fillMaxSize() )
瞭解詳情
如要進一步瞭解如何在 Compose 中繪圖,請參閱下列資源:
- 圖形修飾符 - 瞭解各種繪圖修飾符。
- 筆刷 - 瞭解如何自訂內容繪製方式。
- Compose 中的自訂版面配置和圖形 - 2022 年 Android 開發人員高峰會 - 瞭解如何在 Compose 中利用版面配置和圖形建構自訂 UI。
- JetLagged 範例 - 呈現如何繪製自訂圖形的 Compose 範例。
為您推薦
- 注意:系統會在 JavaScript 關閉時顯示連結文字
- 圖形修飾符
- Compose 中的圖形
- Jetpack Compose 中的對齊線