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의 맞춤 그래픽 및 레이아웃 - Android Dev Summit 2022
- JetLagged 샘플 - RuntimeShader 브러시
추천 서비스
- 참고: JavaScript가 사용 중지되어 있으면 링크 텍스트가 표시됩니다.
- 그래픽 수정자
- Compose의 그래픽
- 텍스트 스타일 지정