یک 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 باید به صورت کسری بین ۰ و ۱ مشخص شود. مقادیر بزرگتر از ۱ باعث میشوند که آن رنگها به عنوان بخشی از گرادیان نمایش داده نشوند.
شما میتوانید نقاط توقف رنگ را طوری تنظیم کنید که مقادیر مختلفی داشته باشند، مثلاً کمتر یا بیشتر از یک رنگ:
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 فقط در صورتی گرادیان را کاشیکاری میکند که اندازه ناحیه بزرگتر از اندازه قلممو باشد.
کد زیر الگوی گرادیان را ۴ بار تکرار میکند، زیرا endX روی 50.dp و size روی 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.Repeated : لبه از آخرین رنگ تا اولین رنگ تکرار میشود. | ![]() |
TileMode.Mirror : لبه از آخرین رنگ به اولین رنگ منعکس میشود. | ![]() |
TileMode.Clamp : لبه به رنگ نهایی گیره میشود. سپس نزدیکترین رنگ را برای بقیه ناحیه رنگ میکند. | ![]() |
TileMode.Decal : فقط تا اندازه مرزها رندر میشود. TileMode.Decal از رنگ مشکی شفاف برای نمونهبرداری از محتوای خارج از مرزهای اصلی استفاده میکند در حالی که TileMode.Clamp از رنگ لبه نمونهبرداری میکند. | ![]() |
TileMode برای سایر گرادیانهای جهتدار نیز به روشی مشابه عمل میکند، تفاوت در جهت تکرار است.
تغییر اندازه قلم مو
اگر اندازه ناحیهای که قلممو در آن کشیده خواهد شد را میدانید، میتوانید endX کاشی را همانطور که در بالا در بخش TileMode دیدیم تنظیم کنید. اگر در DrawScope هستید، میتوانید از ویژگی size آن برای بدست آوردن اندازه ناحیه استفاده کنید.
اگر اندازه ناحیه طراحی خود را نمیدانید (برای مثال اگر Brush به متن اختصاص داده شده باشد)، میتوانید Shader گسترش داده و از اندازه ناحیه طراحی در تابع createShader استفاده کنید.
در این مثال، اندازه را بر ۴ تقسیم کنید تا الگو ۴ بار تکرار شود:
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 بارگذاری کنید و یک Brush 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 Shader را ارائه میدهد. Shaderها را میتوان در AGSL نوشت و با یک Brush در Compose استفاده کرد.
برای ایجاد یک براش Shader، ابتدا Shader را به عنوان رشته AGSL shader تعریف کنید:
@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 بین دو رنگ انجام میدهد. این یک جلوه گرادیان ایجاد میکند.
سپس، قلموی سایهزن (Shader Brush) را ایجاد کنید و یونیفرمها را برای 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 - اجلاس توسعهدهندگان اندروید ۲۰۲۲
- نمونه JetLagged - براش RuntimeShader
برای شما توصیه میشود
- توجه: متن لینک زمانی نمایش داده میشود که جاوا اسکریپت غیرفعال باشد.
- اصلاحکنندههای گرافیکی
- گرافیک در نوشتن
- متن سبک







