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 و اندازه روی 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 به Text اختصاص داده شده است)، میتوانید 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 بار کنید،
و قلمموی 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 را ارائه میدهد. سایهزنها را میتوان در 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 بین دو رنگ انجام میدهد. این کار جلوه گرادیان ایجاد میکند.
سپس، 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 مراجعه کنید.
منابع بیشتر
برای نمونههای بیشتر از استفاده از Brush در Compose، منابع زیر را بررسی کنید:
- رنگآمیزی نوشتار با قلمموی پویانمایی در Compose 🖌️
- گرافیک و چیدمان سفارشی در Compose - نشست توسعهدهندگان Android ۲۰۲۲
- JetLagged Sample - RuntimeShader Brush
توصیهشده برای شما
- توجه: وقتی جاوا اسکریپت خاموش باشد، نوشتار پیوند نمایش داده میشود
- اصلاحکنندههای گرافیک
- گرافیک در Compose
- سبکبندی نوشتار