Brush
ใน Compose จะอธิบายวิธีวาดสิ่งต่างๆ บนหน้าจอ โดยจะ
กำหนดสีที่จะวาดในพื้นที่วาด (เช่น วงกลม
สี่เหลี่ยมจัตุรัส เส้นทาง) มีแปรงในตัวบางอย่างที่มีประโยชน์สำหรับการวาด เช่น 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
pair โดยมีสีเหลืองน้อยกว่าสีแดงและสีน้ำเงิน

ทำซ้ำรูปแบบด้วย 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
ทำงานในลักษณะเดียวกันกับไล่ระดับสีแบบมีทิศทางอื่นๆ โดย
ความแตกต่างคือทิศทางที่การทำซ้ำเกิดขึ้น
เปลี่ยนขนาดแปรง
หากทราบขนาดของพื้นที่ที่จะวาดแปรง คุณสามารถตั้งค่าไทล์ endX
ตามที่เห็นด้านบนในส่วน TileMode
หากอยู่ใน 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
จะ
จัดสรร Shader
ใหม่ภายในหากขนาดแตกต่างจากการ
สร้าง Brush
ครั้งล่าสุด หรือหากออบเจ็กต์สถานะที่ใช้ในการสร้างเชเดอร์มีการ
เปลี่ยนแปลง
โค้ดต่อไปนี้จะสร้าง Shader 3 ครั้งโดยมีขนาดแตกต่างกัน เมื่อขนาดของพื้นที่วาดภาพเปลี่ยนแปลง
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))
โดยจะใช้แปรงกับภาพวาดประเภทต่างๆ ได้แก่ พื้นหลัง ข้อความ และ Canvas ซึ่งจะแสดงผลดังนี้

โปรดสังเกตว่าตอนนี้ข้อความยังแสดงผลโดยใช้ ImageBitmap
เพื่อวาด
พิกเซลสำหรับข้อความด้วย
ตัวอย่างขั้นสูง: แปรงที่กำหนดเอง
แปรง AGSL RuntimeShader
AGSL มีความสามารถของ Shader GLSL บางส่วน ตัวปรับแสงเงาสามารถ เขียนใน AGSL และใช้กับแปรงใน Compose ได้
หากต้องการสร้างแปรง Shader ให้กำหนด Shader เป็นสตริง Shader ของ 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()
Shader ด้านบนรับสีอินพุต 2 สี คำนวณระยะทางจากด้านล่าง
ซ้าย (vec2(0, 1)
) ของพื้นที่วาด และทำ mix
ระหว่าง 2 สี
ตามระยะทาง ซึ่งจะสร้างเอฟเฟกต์การไล่ระดับสี
จากนั้นสร้าง Shader Brush และตั้งค่า Uniform สำหรับ 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) ) }
เมื่อเรียกใช้คำสั่งนี้ คุณจะเห็นผลลัพธ์ต่อไปนี้แสดงบนหน้าจอ

โปรดทราบว่าคุณทำสิ่งต่างๆ ได้มากมายด้วย Shader ไม่ใช่แค่การไล่ระดับสี เนื่องจาก Shader เป็นการคำนวณที่อิงตามคณิตศาสตร์ทั้งหมด ดูข้อมูลเพิ่มเติมเกี่ยวกับ AGSL ได้ที่เอกสารประกอบของ AGSL
แหล่งข้อมูลเพิ่มเติม
ดูตัวอย่างเพิ่มเติมเกี่ยวกับการใช้ Brush ใน Compose ได้จากแหล่งข้อมูลต่อไปนี้
- การทำให้การระบายสีข้อความด้วยแปรงใน Compose เคลื่อนไหว 🖌️
- กราฟิกและเลย์เอาต์ที่กำหนดเองใน Compose - Android Dev Summit 2022
- JetLagged Sample - RuntimeShader Brush
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- ตัวปรับแต่งกราฟิก
- กราฟิกในฟีเจอร์เขียน
- จัดรูปแบบข้อความ