Compose 中的 Brush
說明瞭如何在螢幕上繪圖:判斷在繪圖區域 (即圓形、正方形、路徑) 所繪製的顏色。提供了幾個內建的繪圖專用筆刷,如 LinearGradient
、RadialGradient
或純色 SolidColor
筆刷。
您可以使用筆刷搭配 Modifier.background()
、TextStyle
或 DrawScope
繪製呼叫,對繪製的內容套用繪製風格。
舉例來說,您可以在 DrawScope
中套用水平漸層筆刷來繪製圓形:
val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue)) Canvas( modifier = Modifier.size(200.dp), onDraw = { drawCircle(brush) } )
漸層筆刷
提供許多內建的漸層筆刷,可用於實現不同的漸層效果。這些筆刷可讓您指定想要在其中建立漸層的顏色清單。
可用的漸層筆刷清單及其相應輸出:
漸層筆刷類型 | 輸出 |
---|---|
Brush.horizontalGradient(colorList) |
|
Brush.linearGradient(colorList) |
|
Brush.verticalGradient(colorList) |
|
Brush.sweepGradient(colorList)
注意:如要在各個顏色之間順暢轉換,請將最後一種顏色設定為起始顏色。 |
|
Brush.radialGradient(colorList) |
使用 colorStops
變更色彩分佈
如要自訂色彩在漸層中出現的方式,可以調整每種顏色的 colorStops
值。colorStops
應指定為介於 0 至 1 之間的分數。如果值大於 1,則不會在部分漸層中呈現這些顏色。
您可以在顏色停止點設定不同的顏色數量,例如使用一種或多種顏色:
val colorStops = arrayOf( 0.0f to Color.Yellow, 0.2f to Color.Red, 1f to Color.Blue ) Box( modifier = Modifier .requiredSize(200.dp) .background(Brush.horizontalGradient(colorStops = colorStops)) )
顏色會依照 colorStop
配對中定義的補償值分散,如黃色比紅色和藍色少。
使用 TileMode
重複圖案
每種漸層筆刷都可以選擇在其上設定 TileMode
。如果您並未設定漸層開始和結束,則可能不會注意到 TileMode
,因為預設會填滿整個區域。只有在區域大小超過筆刷大小時,TileMode
才會顯示漸層圖塊。
以下程式碼會重複漸層模式 4 次,因為 endX
已設定為 50.dp
,且大小已設定為 200.dp
:
val listColors = listOf(Color.Yellow, Color.Red, Color.Blue) val tileSize = with(LocalDensity.current) { 50.dp.toPx() } Box( modifier = Modifier .requiredSize(200.dp) .background( Brush.horizontalGradient( listColors, endX = tileSize, tileMode = TileMode.Repeated ) ) )
下表詳細說明瞭不同的圖塊模式對上述 HorizontalGradient
範例的作用:
TileMode | 輸出 |
---|---|
TileMode.Repeated :邊緣從最後一種顏色重複到第一種顏色。 |
|
TileMode.Mirror :邊緣從最後一種顏色鏡像到第一種顏色。 |
|
TileMode.Clamp :邊緣被限制為最終顏色。然後對其餘區域繪製最接近的顏色。 |
|
TileMode.Decal :僅在邊界大小內呈現。TileMode.Decal 善用透明黑色,對原始邊界外的內容進行取樣,而 TileMode.Clamp 則是運用邊緣色彩進行取樣。 |
TileMode
的運作方式類似於其他定向漸層,在重複方向出現色差。
變更筆刷大小
如果您知道畫刷所繪製的區域大小,可以如以上 TileMode
章節所述設定圖塊 endX
。如果採用 DrawScope
,可以使用其 size
屬性取得該區域的大小。
如果您不知道所繪製區域的大小 (例如,Brush
指派給文字),可以擴充 Shader
,並以 createShader
函式運用繪製區域大小。
在這個範例中,您可以將大小除以 4,藉此重複 4 次這種模式:
val listColors = listOf(Color.Yellow, Color.Red, Color.Blue) val customBrush = remember { object : ShaderBrush() { override fun createShader(size: Size): Shader { return LinearGradientShader( colors = listColors, from = Offset.Zero, to = Offset(size.width / 4f, 0f), tileMode = TileMode.Mirror ) } } } Box( modifier = Modifier .requiredSize(200.dp) .background(customBrush) )
此外,您還可以變更任何其他漸層的筆刷大小,例如放射漸層。如果未指定大小和中心點,漸層會佔滿 DrawScope
的完整邊界,且放射漸層的中心會預設為 DrawScope
邊界的中心。這樣會使放射漸層的中心以較小維度 (寬度或高度) 顯示:
Box( modifier = Modifier .fillMaxSize() .background( Brush.radialGradient( listOf(Color(0xFF2be4dc), Color(0xFF243484)) ) ) )
在變更放射漸層時,若將半徑大小設定為最大維度,可以看到其放射漸層有更好的效果:
val largeRadialGradient = object : ShaderBrush() { override fun createShader(size: Size): Shader { val biggerDimension = maxOf(size.height, size.width) return RadialGradientShader( colors = listOf(Color(0xFF2be4dc), Color(0xFF243484)), center = size.center, radius = biggerDimension / 2f, colorStops = listOf(0f, 0.95f) ) } } Box( modifier = Modifier .fillMaxSize() .background(largeRadialGradient) )
值得注意的是,傳遞至建立著色器的實際大小取決於叫用的位置。根據預設,如果大小與上次建立 Brush
時不同,或者建立著色器時使用的狀態物件已變更,則 Brush
會在內部重新分配其 Shader
。
使用下列程式碼,可隨著繪製區域的大小變更,以不同的大小建立三種著色器:
val colorStops = arrayOf( 0.0f to Color.Yellow, 0.2f to Color.Red, 1f to Color.Blue ) val brush = Brush.horizontalGradient(colorStops = colorStops) Box( modifier = Modifier .requiredSize(200.dp) .drawBehind { drawRect(brush = brush) // will allocate a shader to occupy the 200 x 200 dp drawing area inset(10f) { /* Will allocate a shader to occupy the 180 x 180 dp drawing area as the inset scope reduces the drawing area by 10 pixels on the left, top, right, bottom sides */ drawRect(brush = brush) inset(5f) { /* will allocate a shader to occupy the 170 x 170 dp drawing area as the inset scope reduces the drawing area by 5 pixels on the left, top, right, bottom sides */ drawRect(brush = brush) } } } )
使用圖片做為筆刷
如要使用 ImageBitmap 做為 Brush
,請將圖片載入為 ImageBitmap
,並建立 ImageShader
筆刷:
val imageBrush = ShaderBrush(ImageShader(ImageBitmap.imageResource(id = R.drawable.dog))) // Use ImageShader Brush with background Box( modifier = Modifier .requiredSize(200.dp) .background(imageBrush) ) // Use ImageShader Brush with TextStyle Text( text = "Hello Android!", style = TextStyle( brush = imageBrush, fontWeight = FontWeight.ExtraBold, fontSize = 36.sp ) ) // Use ImageShader Brush with DrawScope#drawCircle() Canvas(onDraw = { drawCircle(imageBrush) }, modifier = Modifier.size(200.dp))
筆刷適用於多種繪製類型:背景、文字和畫布。這會輸出以下內容:
請注意,現在還可以使用 ImageBitmap
轉譯文字,為文字繪製像素。
進階範例:自訂筆刷
AGSL RuntimeShader
筆刷
AGSL 提供部分 GLSL 著色器功能。可使用 AGSL 編寫著色器,並在 Compose 中與筆刷搭配使用。
如要建立著色器筆刷,首先將著色器定義為 AGSL 著色器字串:
@Language("AGSL") val CUSTOM_SHADER = """ uniform float2 resolution; layout(color) uniform half4 color; layout(color) uniform half4 color2; half4 main(in float2 fragCoord) { float2 uv = fragCoord/resolution.xy; float mixValue = distance(uv, vec2(0, 1)); return mix(color, color2, mixValue); } """.trimIndent()
上方的著色器使用兩種輸入顏色,計算繪製區域左下方 (vec2(0, 1)
) 的距離,並根據距離在兩種顏色之間執行 mix
。這會產生漸層效果。
然後,建立著色器筆刷,並設定 resolution
的樣式 - 繪製區域的大小,以及您要用作自訂輸入的 color
和 color2
漸層:
val Coral = Color(0xFFF3A397) val LightYellow = Color(0xFFF8EE94) @RequiresApi(Build.VERSION_CODES.TIRAMISU) @Composable @Preview fun ShaderBrushExample() { Box( modifier = Modifier .drawWithCache { val shader = RuntimeShader(CUSTOM_SHADER) val shaderBrush = ShaderBrush(shader) shader.setFloatUniform("resolution", size.width, size.height) onDrawBehind { shader.setColorUniform( "color", android.graphics.Color.valueOf( LightYellow.red, LightYellow.green, LightYellow .blue, LightYellow.alpha ) ) shader.setColorUniform( "color2", android.graphics.Color.valueOf( Coral.red, Coral.green, Coral.blue, Coral.alpha ) ) drawRect(shaderBrush) } } .fillMaxWidth() .height(200.dp) ) }
執行完畢後,您可以看到下列顯示的內容:
值得注意的是,除了漸層之外,著色器還可以繪製許多其他效果,因為所有這些採用的是數學運算。如要進一步瞭解 AGSL,請參閱 AGSL 說明文件。
其他資源
如需更多在 Compose 中使用筆刷的範例,請參閱下列資源:
- 在 Compose 中使用動畫筆刷繪製文字顏色 🖌?️
- 在 Compose 中自訂圖形和版面配置 - 2022 年 Android 開發人員高峰會
- JetLagged 範例 - RuntimeShader 筆刷
為您推薦
- 注意:系統會在 JavaScript 關閉時顯示連結文字
- 圖形修飾符
- Compose 中的圖形
- 樣式文字